1909 lines
69 KiB
JavaScript
1909 lines
69 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) 2006-2022 bLAB
|
|
** $CREATED: 1-1-19 by sbosse.
|
|
** $VERSION: 1.8.1
|
|
** $RCS: $Id:$
|
|
** $INFO:
|
|
**
|
|
** Main Application JAM LAB WEBUI
|
|
**
|
|
** $ENDOFINFO
|
|
*/
|
|
|
|
var version = "1.8.3"
|
|
console.log(version)
|
|
var UI= $$;
|
|
var logtext= '';
|
|
var treemap=[];
|
|
var sourcetext='';
|
|
var printloc=false;
|
|
|
|
var shell=[];
|
|
var shellWin=[];
|
|
var infoShellWin=[];
|
|
var configShellWin=[];
|
|
var shellNum=1;
|
|
var monitorWin=[];
|
|
var monitorNum=1;
|
|
var monitor=[]
|
|
var reporterWin=[];
|
|
var reporterNum=1;
|
|
var editor=[];
|
|
var editorWin=[];
|
|
var editorNum=1;
|
|
var configEditorWin=[];
|
|
var netNodes=[]
|
|
var state=0;
|
|
var cookieConfig = 'jam.webui.config';
|
|
var help={md:{}};
|
|
var Marked;
|
|
|
|
if (typeof jamConfig == 'undefined') info ('No custom configuration file config.js loaded.')
|
|
else info ('Custom configuration file config.js loaded.');
|
|
|
|
/** Main Options **/
|
|
|
|
// Optional App configuration loaded from file (config.js)
|
|
if (typeof jamConfig == 'undefined') jamConfig = {
|
|
name : '?',
|
|
link1:{ip:"ag-0.de", ipport:10001, proto:'http', secure:'', enable:true, shells:[1]},
|
|
link2:{ip:"localhost",ipport:10001, proto:'http', secure:'', enable:false, shells:[1]},
|
|
link3:{ip:"",ipport:0, proto:'http', secure:'', enable:false, shells:[1]},
|
|
link4:{ip:"",ipport:0, proto:'http', secure:'', enable:false, shells:[1]},
|
|
log:{agent:true,parent:false,time:false,Time:true,class:false}, // Message flags: agent parent time class
|
|
fontsize: 14,
|
|
group:'jamweb',
|
|
user:'user',
|
|
workdir : '/',
|
|
webclipTime:300,
|
|
webclipUrl:'edu-9.de:9176',
|
|
}
|
|
jamConfig.version=version;
|
|
|
|
// load config from cookie
|
|
function loadConfig() {
|
|
var data = typeof localStorage=='undefined'?Utils.getCookie(cookieConfig):localStorage.getItem(cookieConfig);
|
|
if (!data) data=Utils.getCookie(cookieConfig);
|
|
if (data) {
|
|
console.log('Loaded jamConfig from cookie '+cookieConfig);
|
|
var obj = JSON.parse(data);
|
|
delete obj.version;
|
|
Object.assign(jamConfig,obj);
|
|
/*
|
|
jamConfig.link1=obj.link1;
|
|
jamConfig.link2=obj.link2;
|
|
jamConfig.link3=obj.link3;
|
|
jamConfig.link4=obj.link4;
|
|
jamConfig.log=obj.log;
|
|
jamConfig.version=version;
|
|
*/
|
|
}
|
|
}
|
|
function saveConfig() {
|
|
var obj = {}
|
|
/*
|
|
link1:jamConfig.link1,
|
|
link2:jamConfig.link2,
|
|
link3:jamConfig.link3,
|
|
link4:jamConfig.link4,
|
|
log:jamConfig.log,
|
|
}
|
|
*/
|
|
Object.assign(obj,jamConfig);
|
|
console.log('Saving jamConfig in cookie '+cookieConfig);
|
|
var data = JSON.stringify(obj);
|
|
setCookie(cookieConfig,obj,2)
|
|
if (typeof localStorage!='undefined') localStorage.setItem(cookieConfig, data);
|
|
}
|
|
function updateConfig(shell) {
|
|
shell.config({log:jamConfig.log});
|
|
}
|
|
|
|
// get config updates from URL params
|
|
function urlConfig() {
|
|
var params = parseUrl(document.URL);
|
|
console.log(document.URL,params);
|
|
if (params && (params.link||params.link1)) {
|
|
var tokens=(params.link||params.link1).split(':');
|
|
if (tokens.length==2) {
|
|
jamConfig.link1.ip=tokens[0];
|
|
jamConfig.link1.ipport=Number(tokens[1]);
|
|
jamConfig.link1.enable=true;
|
|
}
|
|
}
|
|
if (params && params.link2) {
|
|
var tokens=params.link2.split(':');
|
|
if (tokens.length==2) {
|
|
jamConfig.link2.ip=tokens[0];
|
|
jamConfig.link2.ipport=Number(tokens[1]);
|
|
jamConfig.link2.enable=true;
|
|
}
|
|
}
|
|
if (params && (params.secure||params.secure1)) {
|
|
jamConfig.link1.secure=(params.secure||params.secure1);
|
|
}
|
|
if (params && params.secure2) {
|
|
jamConfig.link2.secure=params.secure2;
|
|
}
|
|
if (params.proto) {
|
|
jamConfig.link1.proto=params.proto;
|
|
jamConfig.link2.proto=params.proto;
|
|
jamConfig.link3.proto=params.proto;
|
|
jamConfig.link4.proto=params.proto;
|
|
}
|
|
}
|
|
loadConfig();
|
|
urlConfig();
|
|
|
|
var classTemplate = "function ac (options) {\n this.x=null;\n this.act = {\n a1: () => {log('Start')},\n a2: () => {log('End');kill()} }\n this.trans = {\n a1:a2\n }\n this.on = {\n signal : function () {}\n }\n this.next = a1\n} "
|
|
|
|
|
|
// Info and error message toasts ...
|
|
function info (text) {
|
|
webix.message({text:text,type:'Info'})
|
|
}
|
|
|
|
function error (text) {
|
|
webix.message({text:text,type:'error'})
|
|
}
|
|
|
|
function clear (widget) {
|
|
var view = UI(widget);
|
|
var log = UI(widget+'LogText');
|
|
var scroll = view.getBody();
|
|
logtext = '';
|
|
log.removeView(widget+'LogTextView');
|
|
log.addView({template:'<pre>'+logtext+'</pre>', autoheight:true, borderless:true, id:widget+'LogTextView'});
|
|
scroll.scrollTo(0,1000000)
|
|
view.show();
|
|
}
|
|
|
|
function deltree() {
|
|
var root,tree = this.UI('navTree');
|
|
if (tree._roots) {
|
|
for (var p in tree._roots) {
|
|
p=tree._roots[p];
|
|
tree.remove(p);
|
|
}
|
|
} else tree.remove('root');
|
|
root={ id:"root", open:true, value:'Nodes @'+SHELL.Io.Time() }
|
|
tree.add(root);
|
|
}
|
|
|
|
function maketree() {
|
|
var i=0,tree = this.UI('navTree');
|
|
for(var p in netNodes) {
|
|
tree.add({id:p,value:netNodes[p]+' '+p},i,'root');
|
|
i++;
|
|
}
|
|
}
|
|
|
|
|
|
// Update node information view in shell window
|
|
async function updateInfo(shellcmd, shellnum) {
|
|
var node = await shellcmd.info('node').id,
|
|
stats = await shellcmd.stats('node');
|
|
function makeTree(element,root) {
|
|
var i=0;
|
|
var rows=[];
|
|
if (element == undefined)
|
|
return { id:root+'-'+i, value:'null' }
|
|
else if (typeof element == 'number' ||
|
|
typeof element == 'string' ||
|
|
typeof element == 'boolean')
|
|
return { id:root+'-'+i, value:String(element) }
|
|
else if (typeof element == 'function')
|
|
return { id:root+'-'+i, value:'function' }
|
|
else if (typeof element == 'object') {
|
|
for(var p in element) {
|
|
if (p=='self') continue;
|
|
var tree=makeTree(element[p],root+'-'+i);
|
|
if (!tree) continue;
|
|
if (tree && tree.length)
|
|
rows.push({ id:root+'-'+i, open:false, value:p, data : tree});
|
|
else {
|
|
tree.value=p+'='+tree.value;
|
|
rows.push(tree);
|
|
}
|
|
i++;
|
|
}
|
|
return rows
|
|
}
|
|
}
|
|
var rows = [
|
|
{ view:'label', label:'<b>Node '+node+'</b>', height:18}
|
|
]
|
|
var agents = await shellcmd.stats('agent');
|
|
var i = 1, height=50;
|
|
var treeAgents = [];
|
|
function click(o) { console.log(o) }
|
|
for(var p in agents) {
|
|
var info='agent.'+p+' pid='+agents[p].pid+' class='+agents[p].class+' state='+agents[p].state;
|
|
var agent = await shellcmd.info('agent-data',p);
|
|
treeAgents.push({ id:info, open:false, value:p, data : [
|
|
{ id:info+'-'+0, value:'class='+agents[p].class },
|
|
{ id:info+'-'+1, value:'pid='+agents[p].pid },
|
|
{ id:info+'-'+2, value:'gid='+agents[p].gid },
|
|
{ id:info+'-'+3, value:'parent='+agents[p].parent },
|
|
{ id:info+'-'+4, value:'state='+agents[p].state },
|
|
{ id:info+'-'+5, value:'next='+agents[p].next },
|
|
{ id:info+'-'+6, value:'time='+agents[p].resources.consumed },
|
|
{ id:info+'-'+7, open:false, value:'agent', data : makeTree(agent,info+'-'+7)},
|
|
]});
|
|
i++;
|
|
}
|
|
height=50+i*25;
|
|
var tree1 = {
|
|
view:"tree",
|
|
id:'treeAgentsNode'+shellnum,
|
|
select:true,
|
|
tooltip:true,
|
|
height:'auto',
|
|
data: [
|
|
{id:"root", value:"Agents", open:true, data:treeAgents}
|
|
],
|
|
on:{
|
|
// the default click behavior that is true for any datatable cell
|
|
"onItemClick":function(id, e, trg){
|
|
if (id.indexOf('agent.')==0) {
|
|
|
|
}
|
|
}
|
|
},
|
|
}
|
|
rows.push(tree1)
|
|
for (var p in stats) rows.push({ view:"text", label:p, readonly:true, type:'text', value:stats[p].toString()})
|
|
return rows;
|
|
}
|
|
|
|
// Update window pull-down menus
|
|
function updateMenu() {
|
|
var i,items=[];
|
|
UI('menuShells').clearAll();
|
|
for(i in shellWin) items.push((i)+' : '+shellWin[i]._options.name);
|
|
UI('menuShells').add({value:"Shells", submenu:items});
|
|
items=[];
|
|
for(i in editorWin) items.push((i)+' : '+editorWin[i]._options.file);
|
|
UI('menuEditors').clearAll();
|
|
UI('menuEditors').add({value:"Editors", submenu:items});
|
|
items=[];
|
|
for(i in monitorWin) items.push((i)+' : '+monitorWin[i]._options.name);
|
|
UI('menuMonitors').clearAll();
|
|
UI('menuMonitors').add({value:"Monitors", submenu:items});
|
|
}
|
|
|
|
// Update conenction tree
|
|
async function updateConn(cmd,name) {
|
|
var links = await cmd.connected(DIR.IP('%')),
|
|
ips = await cmd.connected(DIR.IP('*'));
|
|
// netNodes={};
|
|
for(var i in netNodes) {
|
|
if (i.indexOf(name)==0) delete netNodes[i];
|
|
}
|
|
for(var i in links) netNodes[name+':'+links[i]]=ips[i];
|
|
deltree();
|
|
maketree();
|
|
}
|
|
|
|
function removeConn(name) {
|
|
for(var i in netNodes) {
|
|
if (i.indexOf(name)==0) delete netNodes[i];
|
|
}
|
|
deltree();
|
|
maketree();
|
|
}
|
|
function autoLayout() {
|
|
var x=0,
|
|
y=50;
|
|
for(i in shellWin) {
|
|
var shell=shellWin[i];
|
|
if (!shell) continue;
|
|
var size=shell.collapse(true);
|
|
x=$('body').width()-size.width;
|
|
shell.window.setPosition(x,y);
|
|
y+=(size.height+1);
|
|
}
|
|
for(i in editorWin) {
|
|
var shell=editorWin[i];
|
|
if (!shell) continue;
|
|
var size=shell.collapse(true);
|
|
x=$('body').width()-size.width;
|
|
shell.window.setPosition(x,y);
|
|
y+=(size.height+1);
|
|
}
|
|
for(i in monitorWin) {
|
|
var shell=monitorWin[i];
|
|
if (!shell) continue;
|
|
var size=shell.collapse(true);
|
|
x=$('body').width()-size.width;
|
|
shell.window.setPosition(x,y);
|
|
y+=(size.height+1);
|
|
}
|
|
}
|
|
|
|
/************ NETWORK ***************/
|
|
Network = {
|
|
state:0,
|
|
start: async function () {
|
|
if (Network.state<2) {
|
|
var proto=jamConfig.link1.proto||'http';
|
|
for(var i in shell) {
|
|
if (shell[i] && shell[i].options.shell && !shell[i].port)
|
|
shell[i].port=await shell[i].options.cmd.port(DIR.IP(),{proto:proto,verbose:shell[i].options.log.Network});
|
|
}
|
|
Network.state=1;
|
|
}
|
|
for(var i in shell) {
|
|
if (!shell[i] || !shell[i].options.shell) continue;
|
|
if (jamConfig.link1.enable && jamConfig.link1.ipport)
|
|
shell[i].options.cmd.connect(DIR.IP(jamConfig.link1.proto+'://'+jamConfig.link1.ip+':'+
|
|
jamConfig.link1.ipport+
|
|
(jamConfig.link1.secure!=''?'?secure='+jamConfig.link1.secure:'')));
|
|
if (jamConfig.link2.enable && jamConfig.link2.ipport)
|
|
shell[i].options.cmd.connect(DIR.IP(jamConfig.link2.proto+'://'+jamConfig.link2.ip+':'+
|
|
jamConfig.link2.ipport+
|
|
(jamConfig.link2.secure!=''?'?secure='+jamConfig.link2.secure:'')));
|
|
if (jamConfig.link3.enable && jamConfig.link3.ipport)
|
|
shell[i].options.cmd.connect(DIR.IP(jamConfig.link3.proto+'://'+jamConfig.link3.ip+':'+
|
|
jamConfig.link3.ipport+
|
|
(jamConfig.link3.secure!=''?'?secure='+jamConfig.link3.secure:'')));
|
|
if (jamConfig.link4.enable && jamConfig.link4.ipport)
|
|
shell[i].options.cmd.connect(DIR.IP(jamConfig.link4.proto+'://'+jamConfig.link4.ip+':'+
|
|
jamConfig.link4.ipport+
|
|
(jamConfig.link4.secure!=''?'?secure='+jamConfig.link4.secure:'')));
|
|
}
|
|
Network.state=2;
|
|
},
|
|
stop: function () {
|
|
for(var i in shell) {
|
|
if (!shell[i] || !shell[i].options.shell) continue;
|
|
// disconnect w/o proto!!
|
|
if (jamConfig.link1.enable)
|
|
shell[i].options.cmd.disconnect(DIR.IP(jamConfig.link1.ip+':'+
|
|
jamConfig.link1.ipport));
|
|
if (jamConfig.link2.enable)
|
|
shell[i].options.cmd.disconnect(DIR.IP(jamConfig.link2.ip+':'+
|
|
jamConfig.link2.ipport));
|
|
if (jamConfig.link3.enable)
|
|
shell[i].options.cmd.disconnect(DIR.IP(jamConfig.link3.ip+':'+
|
|
jamConfig.link3.ipport));
|
|
if (jamConfig.link4.enable)
|
|
shell[i].options.cmd.disconnect(DIR.IP(jamConfig.link4.ip+':'+
|
|
jamConfig.link4.ipport));
|
|
}
|
|
Network.state=1;
|
|
},
|
|
update : function (options,num) {
|
|
if (shell[num].port) shell[num].port.amp.config(options);
|
|
}
|
|
}
|
|
jam = {
|
|
state:0,
|
|
start: function () {
|
|
for(var i in shell) {
|
|
if (shell[i] && shell[i].options.shell) shell[i].options.shell.env.start();
|
|
}
|
|
jam.state=1;
|
|
},
|
|
stop: function () {
|
|
for(var i in shell) {
|
|
if (shell[i] && shell[i].options.shell) shell[i].options.shell.env.stop();
|
|
}
|
|
jam.state=0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************ TOP TOOLBAR ********/
|
|
|
|
toolbar = this.webix.ui({
|
|
view:"toolbar",
|
|
id:"myToolbar",
|
|
left:0, top:0, width:'100%',
|
|
cols:[
|
|
{ view:"button", type:"icon", icon:"play", id:'button.jam.start', tooltip:'Start', width:30, click:function () {
|
|
if (jam.state==0) {
|
|
UI('button.jam.start').disable();
|
|
UI('button.jam.stop').enable();
|
|
jam.start();
|
|
}
|
|
}},
|
|
{ view:"button", type:"icon", icon:"stop", id:'button.jam.stop', tooltip:'Stop', width:30, click:function () {
|
|
UI('button.jam.start').enable();
|
|
UI('button.jam.stop').disable();
|
|
jam.stop();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"chain", id:'button.net.start', tooltip:'Connect', width:30, click:function () {
|
|
if (Network.state<2) {
|
|
UI('button.net.start').disable();
|
|
UI('button.net.stop').enable();
|
|
Network.start();
|
|
}
|
|
}},
|
|
{ view:"button", type:"icon", icon:"chain-broken", id:'button.net.stop', tooltip:'Disconnect', width:30, click:function () {
|
|
UI('button.net.start').enable();
|
|
UI('button.net.stop').disable();
|
|
Network.stop();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"navicon", tooltip:'Configuration', width:30, click:function () {
|
|
mainConfigWin.show();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"plus", tooltip:'New Shell Worker', width:30, click:function () {
|
|
createShell(shellNum,{worker:true});
|
|
shellNum++;
|
|
}},
|
|
{ view:"button", type:"icon", icon:"sort-amount-asc", tooltip:'Bigger Fonts', width:30, click:function () {
|
|
jamConfig.fontsize++;
|
|
changeCSS('.input','font-size',jamConfig.fontsize+'px')
|
|
changeCSS('.normalInput','font-size',jamConfig.fontsize+'px')
|
|
changeCSS('.normalOutput','font-size',jamConfig.fontsize+'px')
|
|
changeCSS('.error','font-size',jamConfig.fontsize+'px')
|
|
changeCSS('.webix_view','font-size',jamConfig.fontsize+'px')
|
|
}},
|
|
{ view:"button", type:"icon", icon:"sort-amount-desc", tooltip:'Smaller Fonts', width:30, click:function () {
|
|
jamConfig.fontsize--;
|
|
changeCSS('.input','font-size',jamConfig.fontsize+'px')
|
|
changeCSS('.normalInput','font-size',jamConfig.fontsize+'px')
|
|
changeCSS('.normalOutput','font-size',jamConfig.fontsize+'px')
|
|
changeCSS('.error','font-size',jamConfig.fontsize+'px')
|
|
changeCSS('.webix_view','font-size',jamConfig.fontsize+'px')
|
|
}},
|
|
{ view:"button", type:"icon", icon:"user-plus", tooltip:'Chat Dialog', width:30, click:function () {
|
|
if (chatWin.isVisible())
|
|
chatWin.hide();
|
|
else {
|
|
chatWin.show();
|
|
chatInit();
|
|
}
|
|
}},
|
|
{ view:"button", type:"icon", icon:"hand-o-right", tooltip:'Visual Pointer', width:30, click:function () {
|
|
var el = document.getElementsByTagName("body")[0];
|
|
self._cursorToggle=!self._cursorToggle;
|
|
if (self._cursorToggle)
|
|
el.style.cursor = "url(redpointer.png), auto";
|
|
else
|
|
el.style.cursor = "auto";
|
|
['webix_view'].forEach(function (id) {
|
|
var ell = document.getElementsByClassName(id);
|
|
if (!ell) return;
|
|
ell.forEach(function (el) {
|
|
if (self._cursorToggle)
|
|
el.style.cursor = "url(redpointer.png), auto";
|
|
else
|
|
el.style.cursor = "auto";
|
|
});
|
|
})
|
|
}},
|
|
{ view:"button", type:"icon", icon:"question", tooltip:'Help', width:30, click:function () {
|
|
helpWin.show();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"th", tooltip:'Auto Layout', width:30, click:function () {
|
|
autoLayout()
|
|
}},
|
|
{ view:"button", type:"icon", icon:"terminal", tooltip:'New Developer Console', width:30, click:function () {
|
|
var shell = Shell.default({
|
|
label:'Developer Console (JS)',
|
|
hide:false,
|
|
editor:true,
|
|
});
|
|
shell.run = function (code) {
|
|
var ___error;
|
|
with ({
|
|
error:shell.env.error,
|
|
keys:Object.keys.bind(Object),
|
|
load:Utils.loadScript,
|
|
print:shell.env.print,
|
|
time:Date.now,
|
|
}) { try { var result = eval(code) } catch (e) { ___error=result=e }};
|
|
if (!code.match(/;[ ]*$/))
|
|
shell.env.print(result);
|
|
else if (___error) shell.env.error(___error);
|
|
}
|
|
}},
|
|
{
|
|
view:"menu",
|
|
id:"menuShells",
|
|
autowidth:true,
|
|
width:100,
|
|
data:[ //menu data
|
|
{ value:"Shells", submenu:["1"] },
|
|
],
|
|
type:{
|
|
subsign:true,
|
|
},
|
|
on:{
|
|
onMenuItemClick:function(id){
|
|
var name = this.getMenuItem(id).value.split(':');
|
|
var win=shellWin[Number(name[0])].window;
|
|
if (win) win.isVisible()?win.hide():win.show();
|
|
}
|
|
}
|
|
},
|
|
{
|
|
view:"menu",
|
|
id:"menuEditors",
|
|
autowidth:true,
|
|
width:100,
|
|
data:[ //menu data
|
|
{ value:"Editors", submenu:[] },
|
|
],
|
|
type:{
|
|
subsign:true,
|
|
},
|
|
on:{
|
|
onMenuItemClick:function(id){
|
|
var name = this.getMenuItem(id).value.split(':');
|
|
var win=editorWin[Number(name[0])].window;
|
|
if (win) win.isVisible()?win.hide():win.show();
|
|
}
|
|
}
|
|
},
|
|
{
|
|
view:"menu",
|
|
id:"menuMonitors",
|
|
autowidth:true,
|
|
width:100,
|
|
data:[ //menu data
|
|
{ value:"Monitors", submenu:[] },
|
|
],
|
|
type:{
|
|
subsign:true,
|
|
},
|
|
on:{
|
|
onMenuItemClick:function(id){
|
|
var name = this.getMenuItem(id).value.split(':');
|
|
var win=monitorWin[Number(name[0])].window;
|
|
if (win) win.isVisible()?win.hide():win.show();
|
|
}
|
|
}
|
|
},
|
|
{ view:"label", id:'myTopLabel', label:'JAM Laboratory WEB API (C) Dr. Stefan Bosse Ver. '+jamConfig.version, align:'right'},
|
|
{ view:"button", type:"icon", icon:"close", tooltip:'Exit', width:30, click:function () {
|
|
}},
|
|
]
|
|
});
|
|
UI('button.jam.stop').disable();
|
|
UI('button.net.stop').disable();
|
|
toolbar.show();
|
|
|
|
|
|
/************ MAIN CONFIG ********/
|
|
mainConfigWin=webix.ui({
|
|
id:'mainConfigWin',
|
|
view:"window",
|
|
width:300,
|
|
height:450,
|
|
left:90, top:90,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
head: {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"label", label:"Main Configuration", align:'right'},
|
|
{ view:"button", type:"icon", icon:"check-square", align:'center', width:30, click: function () {
|
|
jamConfig.link1.ip=UI('mainConfigWinLink1IPAddress').getValue();
|
|
jamConfig.link1.ipport=UI('mainConfigWinLink1IPPort').getValue();
|
|
jamConfig.link1.proto=UI('mainConfigWinLink1IPProto').getValue();
|
|
jamConfig.link1.secure=UI('mainConfigWinLink1SecPort').getValue();
|
|
jamConfig.link2.ip=UI('mainConfigWinLink2IPAddress').getValue();
|
|
jamConfig.link2.ipport=UI('mainConfigWinLink2IPPort').getValue();
|
|
jamConfig.link2.proto=UI('mainConfigWinLink2IPProto').getValue();
|
|
jamConfig.link2.secure=UI('mainConfigWinLink2SecPort').getValue();
|
|
jamConfig.link3.ip=UI('mainConfigWinLink3IPAddress').getValue();
|
|
jamConfig.link3.ipport=UI('mainConfigWinLink3IPPort').getValue();
|
|
jamConfig.link3.proto=UI('mainConfigWinLink3IPProto').getValue();
|
|
jamConfig.link3.secure=UI('mainConfigWinLink3SecPort').getValue();
|
|
jamConfig.link4.ip=UI('mainConfigWinLink4IPAddress').getValue();
|
|
jamConfig.link4.ipport=UI('mainConfigWinLink4IPPort').getValue();
|
|
jamConfig.link4.proto=UI('mainConfigWinLink4IPProto').getValue();
|
|
jamConfig.link4.secure=UI('mainConfigWinLink4SecPort').getValue();
|
|
jamConfig.webclipUrl=UI('mainConfigWinClipUrl').getValue();
|
|
jamConfig.user=UI('mainConfigWinUser').getValue();
|
|
jamConfig.workdir=UI('mainConfigWinWorkdir').getValue();
|
|
saveConfig();
|
|
mainConfigWin.hide();
|
|
}}
|
|
]
|
|
},
|
|
body: {
|
|
rows:[
|
|
{ view:"form", scroll:true, width:300, height:400, elements: [
|
|
|
|
{ view:"label", label:"<b>JAM Network Link 1</b>", height:'18px', align:'left'},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"Enable", height:'18px', value:jamConfig.link1.enable?1:0,
|
|
click: function (o) {jamConfig.link1.enable=Number(self.UI(o).getValue())?true:false}},
|
|
{ view:"text", id:"mainConfigWinLink1IPAddress", label:"IP Address", value:jamConfig.link1.ip},
|
|
{ view:"text", id:"mainConfigWinLink1IPPort", label:"IP Port", value:jamConfig.link1.ipport},
|
|
{ view:"text", id:"mainConfigWinLink1IPProto", label:"IP Proto", value:jamConfig.link1.proto},
|
|
{ view:"text", id:"mainConfigWinLink1SecPort", label:"Secure Port (Opt.)", value:jamConfig.link1.secure},
|
|
|
|
{ view:"label", label:"<b>JAM Network Link 2</b>", height:'18px', align:'left'},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"Enable", height:'18px', value:jamConfig.link2.enable?1:0,
|
|
click: function (o) {jamConfig.link2.enable=Number(self.UI(o).getValue())?true:false}},
|
|
{ view:"text", id:"mainConfigWinLink2IPAddress", label:"IP Address", value:jamConfig.link2.ip},
|
|
{ view:"text", id:"mainConfigWinLink2IPPort", label:"IP Port", value:jamConfig.link2.ipport},
|
|
{ view:"text", id:"mainConfigWinLink2IPProto", label:"IP Proto", value:jamConfig.link2.proto},
|
|
{ view:"text", id:"mainConfigWinLink2SecPort", label:"Secure Port (Opt.)", value:jamConfig.link2.secure},
|
|
|
|
{ view:"label", label:"<b>JAM Network Link 3</b>", height:'18px', align:'left'},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"Enable", height:'18px', value:jamConfig.link3.enable?1:0,
|
|
click: function (o) {jamConfig.link3.enable=Number(self.UI(o).getValue())?true:false}},
|
|
{ view:"text", id:"mainConfigWinLink3IPAddress", label:"IP Address", value:jamConfig.link3.ip},
|
|
{ view:"text", id:"mainConfigWinLink3IPPort", label:"IP Port", value:jamConfig.link3.ipport},
|
|
{ view:"text", id:"mainConfigWinLink3IPProto", label:"IP Proto", value:jamConfig.link3.proto},
|
|
{ view:"text", id:"mainConfigWinLink3SecPort", label:"Secure Port (Opt.)", value:jamConfig.link3.secure},
|
|
|
|
{ view:"label", label:"<b>JAM Network Link 4</b>", height:'18px', align:'left'},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"Enable", height:'18px', value:jamConfig.link4.enable?1:0,
|
|
click: function (o) {jamConfig.link4.enable=Number(self.UI(o).getValue())?true:false}},
|
|
{ view:"text", id:"mainConfigWinLink4IPAddress", label:"IP Address", value:jamConfig.link4.ip},
|
|
{ view:"text", id:"mainConfigWinLink4IPPort", label:"IP Port", value:jamConfig.link4.ipport},
|
|
{ view:"text", id:"mainConfigWinLink4IPProto", label:"IP Proto", value:jamConfig.link4.proto},
|
|
{ view:"text", id:"mainConfigWinLink4SecPort", label:"Secure Port (Opt.)", value:jamConfig.link4.secure},
|
|
|
|
{ view:"label", label:"<b>WebClipboard</b>", height:'18px', align:'left'},
|
|
{ view:"text", id:"mainConfigWinClipUrl", label:"URL", value:jamConfig.webclipUrl},
|
|
{ view:"text", id:"mainConfigWinUser", label:"User", value:jamConfig.user},
|
|
{ view:"text", id:"mainConfigWinWorkdir", label:"WorkDir", value:jamConfig.workdir},
|
|
]}
|
|
]
|
|
}
|
|
});
|
|
|
|
|
|
helpWin=webix.ui({
|
|
id:'helpWin',
|
|
view:"window",
|
|
width:500,
|
|
height:450,
|
|
left:90, top:90,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'gray_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"button", value:'JAMSH', align:'center', click: function () {
|
|
if (helpWin._view) UI('helpWinScrollView').removeView(helpWin._view);
|
|
var helpRendered=help.md.jamsh?help.md.jamsh:Marked(help.jamsh);
|
|
help.md.jamsh=helpRendered;
|
|
helpWin._view=UI('helpWinScrollView').addView(
|
|
{
|
|
rows : [
|
|
{template:'<div class="marked">'+helpRendered+'</div>', autoheight:true}
|
|
]
|
|
}
|
|
);
|
|
}
|
|
},
|
|
{ view:"button", value:'AIOS', align:'center', click: function () {
|
|
if (helpWin._view) UI('helpWinScrollView').removeView(helpWin._view);
|
|
var helpRendered=help.md.aios?help.md.aios:Marked(help.aios);
|
|
help.md.aios=helpRendered;
|
|
helpWin._view=UI('helpWinScrollView').addView(
|
|
{
|
|
rows : [
|
|
{template:'<div class="marked">'+helpRendered+'</div>', autoheight:true}
|
|
]
|
|
}
|
|
);
|
|
}
|
|
},
|
|
{ view:"button", value:'JS', align:'center', click: function () {
|
|
if (helpWin._view) UI('helpWinScrollView').removeView(helpWin._view);
|
|
var helpRendered=help.md.js?help.md.js:Marked(help.js);
|
|
help.md.js=helpRendered;
|
|
helpWin._view=UI('helpWinScrollView').addView(
|
|
{
|
|
rows : [
|
|
{template:'<div class="marked">'+helpRendered+'</div>', autoheight:true}
|
|
]
|
|
}
|
|
);
|
|
}
|
|
},
|
|
{ view:"label", label:"Help", align:'right'},
|
|
{ view:"button", type:"icon", icon:"check-square", align:'center', width:30, click: function () {
|
|
helpWin.hide();
|
|
}}
|
|
]
|
|
},
|
|
body:{
|
|
view : 'scrollview',
|
|
scroll : 'y',
|
|
body : {
|
|
id:'helpWinScrollView',
|
|
rows : [
|
|
]
|
|
}
|
|
}
|
|
});
|
|
|
|
/*********** Network Tree **********/
|
|
navTree=webix.ui({
|
|
id:'navTree',
|
|
left:50, top:50,
|
|
view:'tree',
|
|
type:'lineTree',
|
|
select:true,
|
|
data: [
|
|
{ id:"root", open:true, value:"Not connected!"}
|
|
]
|
|
})
|
|
navTree.show();
|
|
navTree.attachEvent("onAfterSelect", function(id){
|
|
webix.message({text:id,type:'Info'});
|
|
if (id!='root') for (var i in configShellWin) {
|
|
if (configShellWin[i] && configShellWin[i].isVisible()) {
|
|
UI('configRemoteHostIp'+i).setValue(id);
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
|
|
|
|
/************ SHELL ********/
|
|
|
|
// Only one shell (num=1) supported!
|
|
|
|
function _createShell(num,params) {
|
|
shell[num] = winShell(jamConfig); // shell[num].options.shell contains the jamsh object
|
|
var options = shell[num].options;
|
|
var cmd;
|
|
|
|
function Label () {
|
|
return options.name+" / Shell "+num
|
|
}
|
|
|
|
shellWin[num]=webix.ui({
|
|
id:'ShellWin'+num,
|
|
view:"window",
|
|
height:350,
|
|
width:600,
|
|
left:250, top:250,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'red_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"button", type:"icon", icon:"eraser", tooltip:'Clear', width:30, click:function () {
|
|
shell[num].commands.clear()
|
|
}},
|
|
{ view:"button", type:"icon", icon:"navicon", tooltip:'Config', width:30, click:function () {
|
|
configShellWin[num].show();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"edit", tooltip:'New Agent Editor', width:30, click:function () {
|
|
createEditor(editorNum,{shell:num,name:options.name});
|
|
editorNum++;
|
|
}},
|
|
{ view:"button", type:"icon", icon:"envelope", tooltip:'Agent Monitor', width:30, click:function () {
|
|
if (!monitor[num]) {
|
|
createMonitor(num,{shell:shell[num].options.shell})
|
|
} else monitorWin[num].show();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"info", tooltip:'Node Information', width:30, click:function () {
|
|
UI('infoShellWinLabel'+num).setValue("Info / "+Label());
|
|
if (options.infoView) UI('infoShellWinScrollView'+num).removeView(options.infoView);
|
|
options.infoView=UI('infoShellWinScrollView'+num).addView(
|
|
{
|
|
rows : updateInfo(cmd,num)
|
|
}
|
|
);
|
|
infoShellWin[num].show();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"dot-circle-o", tooltip:'Scroll Auto', id:'ShellWinLogFilmBut'+num, width:30, click:function () {
|
|
UI('ShellWinLog'+num).scrollAuto=!UI('ShellWinLog'+num).scrollAuto;
|
|
if (UI('ShellWinLog'+num).scrollAuto) UI('ShellWinLogFilmBut'+num).define('icon','arrow-circle-down')
|
|
else UI('ShellWinLogFilmBut'+num).define('icon','dot-circle-o');
|
|
UI('ShellWinLogFilmBut'+num).refresh();
|
|
}},
|
|
{ view:"label", label:"Shell "+num, id:'ShellWinLabel'+num, align:'right'},
|
|
{ view:"button", type:"icon", icon:"gear", tooltip:'New Script Editor', width:30, click:function () {
|
|
createEditor(editorNum,{shell:num,name:options.name,script:true});
|
|
editorNum++;
|
|
}},
|
|
{ view:"button", type:"icon", icon:"close", tooltip:'Close Shell', width:30, click:function () {
|
|
var self=shellWin[num];
|
|
self.hide();
|
|
}},
|
|
]
|
|
},
|
|
body:{
|
|
id : 'ShellWinLog'+num,
|
|
view : 'scrollview',
|
|
scroll : 'y',
|
|
body : {
|
|
id:'ShellWinLogText'+num,
|
|
rows : [
|
|
{template:('<div id="ShellWinOutput'+num+'" '+
|
|
'spellcheck="false" style="">'), height:"auto", borderless:true},
|
|
{template:('<div><textarea id="ShellWinInput'+num+'" '+
|
|
'class="input" spellcheck="false" wrap="on" onkeydown="shell['+num+
|
|
'].inputKeydown(event)" rows="1" style="width:98%"></textarea></div>'), height:"auto", borderless:true},
|
|
]
|
|
}
|
|
}
|
|
});
|
|
shellWin[num].show();
|
|
|
|
/************** SHELL CONFIG ****************/
|
|
configShellWin[num]=webix.ui({
|
|
id:'configShellWin'+num,
|
|
view:"window",
|
|
width:300,
|
|
height:450,
|
|
left:90, top:90,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'gray_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
id:"configShellWinToolbarWin"+num,
|
|
cols:[
|
|
{ view:"label", label:"Configuration", align:'right'},
|
|
{ view:"button", type:"icon", icon:"check-square", align:'center', width:30, click: function () {
|
|
configShellWin[num].hide();
|
|
updateConfig(cmd);
|
|
saveConfig();
|
|
}}
|
|
]
|
|
},
|
|
body: {
|
|
rows:[
|
|
{ view:"form", scroll:true, width:300, height:400, elements: [
|
|
{ view:'label', label:'<b>Agent Logging</b>', height:0},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"agent", height:'18px', value:jamConfig.log.agent?1:0,
|
|
click: function (o) {jamConfig.log.agent=Number(self.UI(o).getValue())?true:false;}},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"class", height:'18px', value:jamConfig.log.class?1:0,
|
|
click: function (o) {jamConfig.log.class=Number(self.UI(o).getValue())?true:false;}},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"parent", height:'18px', value:jamConfig.log.parent?1:0,
|
|
click: function (o) {jamConfig.log.parent=Number(self.UI(o).getValue())?true:false;}},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"time", height:'18px', value:jamConfig.log.time?1:0,
|
|
click: function (o) {jamConfig.log.time=Number(self.UI(o).getValue())?true:false; }},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"Time", height:'18px', value:jamConfig.log.Time?1:0,
|
|
click: function (o) {jamConfig.log.Time=Number(self.UI(o).getValue())?true:false;}},
|
|
|
|
{ view:'label', label:'<b>Shell Logging</b>', height:0},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"Time", height:'18px', value:options.log.Time?1:0,
|
|
click: function (o) {options.log.Time=Number(self.UI(o).getValue())?true:false;}},
|
|
{ view:"checkbox", customCheckbox:false, labelRight:"Network", height:'18px', value:options.log.Network?1:0,
|
|
click: function (o) {options.log.Network=Number(self.UI(o).getValue())?true:false;
|
|
Network.update({verbose:options.log.Network?1:0},num)}},
|
|
]}
|
|
]
|
|
}
|
|
});
|
|
|
|
/************** SHELL INFO ****************/
|
|
infoShellWin[num]=webix.ui({
|
|
id:'infoShellWin'+num,
|
|
view:"window",
|
|
height:350,
|
|
width:500,
|
|
left:90, top:90,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'gray_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
id:"infoShellWinToolbarWin"+num,
|
|
cols:[
|
|
{ view:"button", type:"icon", icon:"repeat", tooltip:'Refresh', width:30, click:function () {
|
|
if (options.infoView) UI('infoShellWinScrollView'+num).removeView(options.infoView);
|
|
options.infoView=UI('infoShellWinScrollView'+num).addView(
|
|
{
|
|
rows : updateInfo(cmd,num)
|
|
}
|
|
);
|
|
}},
|
|
{ view:"button", type:"icon", icon:"times-circle", tooltip:'Kill Agent', width:30, click:function () {
|
|
var tree = UI('treeAgentsNode'+options.name);
|
|
var selectedId = tree.getSelectedId();
|
|
if (selectedId.indexOf('agent.')==0) {
|
|
var agentid = selectedId.substring(selectedId.indexOf('.')+1,selectedId.indexOf(' '));
|
|
cmd.kill(agentid);
|
|
}
|
|
if (options.infoView) UI('infoShellWinScrollView'+num).removeView(options.infoView);
|
|
options.infoView=UI('infoShellWinScrollView'+num).addView(
|
|
{
|
|
rows : updateInfo(cmd,num)
|
|
}
|
|
);
|
|
}},
|
|
{ view:"label", label:"Info / "+Label(), id:'infoShellWinLabel'+num, align:'right'},
|
|
{ view:"button", type:"icon", icon:"check-square", align:'center', width:30, click: function () {
|
|
infoShellWin[num].hide();
|
|
}}
|
|
]
|
|
},
|
|
body:{
|
|
view : 'form',
|
|
scroll : 'y',
|
|
height: 300,
|
|
id:'infoShellWinScrollView'+num,
|
|
rows : [
|
|
]
|
|
}
|
|
});
|
|
shell[num].init("ShellWinInput"+num,"ShellWinOutput"+num,UI('ShellWinLog'+num));
|
|
UI('ShellWinLog'+num).scrollAuto=false;
|
|
jamConfig.name = options.name;
|
|
cmd = options.cmd;
|
|
shell[num].run=cmd;
|
|
Marked = options.cmd.marked;
|
|
cmd.on('link+',function (arg){
|
|
updateConn(cmd,options.name);
|
|
});
|
|
cmd.on('link-',function (arg){
|
|
updateConn(cmd,options.name);
|
|
});
|
|
|
|
shellWin[num].attachEvent("onViewMove", function(pos, e){
|
|
});
|
|
shellWin[num].attachEvent("onViewMoveEnd", function(pos, e){
|
|
});
|
|
UI('ShellWinLabel'+num).setValue(Label());
|
|
updateMenu();
|
|
var versions = cmd.versions();
|
|
shell[num].print('JAMlib Version '+versions.lib+' JAMShell Version '+versions.shell+' JAMAios Version '+versions.aios);
|
|
}
|
|
|
|
|
|
|
|
|
|
// New shell widget (includes monitor, config, info, and editor widgets, too)
|
|
function createShell(num,params) {
|
|
var shellControl;
|
|
var config = {
|
|
log : Object.assign({},jamConfig.log),
|
|
verbose : jamConfig.verbose||0,
|
|
};
|
|
Object.assign(config,params);
|
|
shellControl = shell[num] = Node(config); // shell[num].options.shell contains the jamsh object
|
|
var options = shell[num].options;
|
|
var cmd;
|
|
function Label () {
|
|
return options.name+' / Shell '+num
|
|
}
|
|
var shellWidget = UI.Shell.default({
|
|
buttons:{
|
|
'config:bars:Configuration' : function () {
|
|
UI.Form.create({
|
|
'Shell Logging':options.log,
|
|
'JAM Logging':config.log,
|
|
},{}, function (_config) {
|
|
Object.assign(config.log,_config['JAM Logging']);
|
|
Object.assign(options.log,_config['Shell Logging']);
|
|
shellWidget.setLabel(Label())
|
|
shellControl.setup(config);
|
|
cmd.config({log:config.log});
|
|
})
|
|
},
|
|
'edit:edit:New Agent Editor' : function () {
|
|
var optionsE = {
|
|
shell:num,
|
|
level:1,
|
|
arguments:'{}',
|
|
file:'agent.js',
|
|
}
|
|
var numed = editorNum++;
|
|
function Label() {
|
|
return optionsE.file+(optionsE.acname? ' ('+optionsE.acname+')':'')+' / '+options.name+' AgE'+numed+':S'+optionsE.shell
|
|
}
|
|
var editorWidget = UI.Editor.default({
|
|
label:Label(),
|
|
mode:'js',
|
|
//x:options.x,
|
|
//y:options.y,
|
|
// hide:false,
|
|
buttons : {
|
|
'config:bars:Configure' : function (label,ev) {
|
|
/********** EDITOR CONFIG ****************/
|
|
if (!configEditorWin[numed]) {
|
|
configEditorWin[numed]=webix.ui({
|
|
id:'configEditorWin'+numed,
|
|
view:"window",
|
|
width:300,
|
|
height:450,
|
|
left:ev.clientX-50, top:ev.clientY,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'gray_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"label", label:"Runtime Configuration", align:'right'},
|
|
{ view:"button", type:"icon", icon:"check-square", align:'center', width:30, click: function () {
|
|
optionsE.arguments = UI('configEditorAgentArgs'+numed).getValue();
|
|
optionsE.level = Number(UI('configEditorAgentLevel'+numed).getValue())||0;
|
|
optionsE.file=UI('configEditorFileName'+numed).getValue();
|
|
editorWidget.setLabel(Label());
|
|
configEditorWin[numed].hide();
|
|
updateMenu();
|
|
}}
|
|
]
|
|
},
|
|
body: {
|
|
rows:[
|
|
{ view:"form", scroll:true, width:300, height:400, elements: [
|
|
{ view:"label", label:"<b>Agent Creation</b>", height:'18px', align:'left'},
|
|
{ view:"textarea", id:"configEditorAgentArgs"+numed, label:"Argument", height:150, value:optionsE.arguments},
|
|
{ view:"text", id:"configEditorAgentLevel"+numed, label:"Level", value:optionsE.level},
|
|
{ view:"label", label:"<b>Code</b>", height:'18px', align:'left'},
|
|
{ view:"text", id:"configEditorFileName"+numed, label:"File Name", value:optionsE.file},
|
|
]}
|
|
]
|
|
}
|
|
});
|
|
}
|
|
configEditorWin[numed].show();
|
|
},
|
|
'compile:indent:Compile Code' : async function () {
|
|
var code = editorWidget.editor.get();
|
|
var acname = await options.shell.env.compile(code);
|
|
if (acname) {
|
|
optionsE.acname=acname;
|
|
editorWidget.setLabel(Label());
|
|
optionsE.compiled=true;
|
|
editorWidget.code=code;
|
|
} else {
|
|
optionsE.compiled=false;
|
|
info('Agent class function not compiled.');
|
|
}
|
|
updateMenu();
|
|
},
|
|
'compile:play:Start Agent' : async function () {
|
|
var code = editorWidget.editor.get();
|
|
if (!optionsE.compiled || code!=editorWidget.code) {
|
|
var acname = options.shell.env.compile(code);
|
|
if (acname) {
|
|
optionsE.acname=acname;
|
|
editorWidget.setLabel(Label());
|
|
optionsE.compiled=true;
|
|
editorWidget.code=code;
|
|
updateMenu();
|
|
} else {
|
|
optionsE.compiled=false
|
|
return info('No agent started, class function not compiled.');
|
|
}
|
|
}
|
|
var ac=optionsE.acname||optionsE.file.replace(/\.js$/,''),args;
|
|
if (optionsE.arguments!="") eval('args='+optionsE.arguments);
|
|
else args={};
|
|
var id=await options.shell.env.create(ac,args,optionsE.level);
|
|
if (id) {
|
|
info('Agent '+id+' of class '+ac+' started.');
|
|
shellControl.commands.print('[JLB] Agent '+id+' of class '+ac+' started.');
|
|
} else {
|
|
error('Starting agent of class '+ac+' failed.');
|
|
shellControl.commands.error('[JLB] Error: Starting agent of class '+ac+' failed.');
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
})
|
|
editorWin[numed]=editorWidget;
|
|
editorWin[numed]._options=optionsE;
|
|
editorWidget.on('file',function (filename) {
|
|
optionsE.file=filename;
|
|
editorWidget.setLabel(Label())
|
|
updateMenu();
|
|
})
|
|
editorWidget.on('close',function () {
|
|
delete editorWin[numed];
|
|
updateMenu();
|
|
})
|
|
editorWin[numed].editor.set(classTemplate);
|
|
updateMenu();
|
|
},
|
|
'monitor:envelope:Agent Monitor' : function () {
|
|
if (!monitorWin[num]) {
|
|
// createMonitor(num,{shell:shell[num].options.shell})
|
|
// TODO
|
|
monitorWidget=UI.Monitor.default({
|
|
label:options.name+' / Monitor S'+num,
|
|
close:false,
|
|
run : function (line) {
|
|
shellControl.question(line);
|
|
}
|
|
})
|
|
monitorWin[num]=monitorWidget;
|
|
monitorWin[num]._options=options;
|
|
options.shell.options.outputAgent = function (line) { monitorWidget.env.print(line) };
|
|
updateMenu();
|
|
} else monitorWin[num].window.show();
|
|
},
|
|
'info:info:Node Information' : async function () {
|
|
UI('infoShellWinLabel'+num).setValue("Info / "+Label());
|
|
if (options.infoView) UI('infoShellWinScrollView'+num).removeView(options.infoView);
|
|
options.infoView=UI('infoShellWinScrollView'+num).addView(
|
|
{
|
|
rows : await updateInfo(cmd,num)
|
|
}
|
|
);
|
|
infoShellWin[num].show();
|
|
},
|
|
'script:gear:New Script Editor': function () {
|
|
var optionsSE = {
|
|
shell:num,
|
|
file:'script.js',
|
|
}
|
|
var numed = editorNum++;
|
|
function Label() {
|
|
return optionsSE.file+' / '+options.name+' ScE'+numed+':S'+optionsSE.shell
|
|
}
|
|
var editorWidget = UI.Editor.default({
|
|
label:Label(),
|
|
mode:'js',
|
|
buttons : {
|
|
'compile:play:Start Agent' : function () {
|
|
var code = editorWidget.editor.get();
|
|
shellControl.options.cmd.exec(code);
|
|
}
|
|
}
|
|
})
|
|
editorWin[numed]=editorWidget;
|
|
editorWin[numed]._options=optionsSE;
|
|
editorWidget.on('file',function (filename) {
|
|
optionsSE.file=filename;
|
|
editorWidget.setLabel(Label())
|
|
updateMenu();
|
|
})
|
|
editorWidget.on('close',function () {
|
|
delete editorWin[numed];
|
|
updateMenu();
|
|
})
|
|
updateMenu();
|
|
}
|
|
},
|
|
run : function (line,env) {
|
|
shellControl.question(line);
|
|
},
|
|
label : Label(),
|
|
close : num>1,
|
|
})
|
|
shellControl.init(shellWidget, async function () {
|
|
shellWin[num]=shellWidget;
|
|
shellWin[num]._options=options;
|
|
shellWidget.on('close', function () {
|
|
shellControl.stop()
|
|
})
|
|
// config.name = options.name;
|
|
cmd = options.cmd;
|
|
shell[num].run=cmd;
|
|
cmd.on('link+',function (arg){
|
|
updateConn(cmd,options.name);
|
|
});
|
|
cmd.on('link-',function (arg){
|
|
updateConn(cmd,options.name);
|
|
});
|
|
if (num==1) Marked = cmd.marked;
|
|
updateMenu();
|
|
var versions = await cmd.versions();
|
|
shellControl.commands.print('JAMlib Version '+versions.lib+' JAMShell Version '+versions.shell+' JAMAios Version '+versions.aios);
|
|
shellWidget.setLabel(Label());
|
|
});
|
|
if (num>1) {
|
|
shellWidget.on('close',function () {
|
|
removeConn(options.name);
|
|
shellControl.stop();
|
|
delete shell[num];
|
|
delete shellWin[num];
|
|
})
|
|
}
|
|
|
|
/************** SHELL INFO MANAGER ****************/
|
|
infoShellWin[num]=webix.ui({
|
|
id:'infoShellWin'+num,
|
|
view:"window",
|
|
height:350,
|
|
width:500,
|
|
left:90, top:90,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'gray_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
id:"infoShellWinToolbarWin"+num,
|
|
cols:[
|
|
{ view:"button", type:"icon", icon:"repeat", tooltip:'Refresh', width:30, click:async function () {
|
|
if (options.infoView) UI('infoShellWinScrollView'+num).removeView(options.infoView);
|
|
options.infoView=UI('infoShellWinScrollView'+num).addView(
|
|
{
|
|
rows : await updateInfo(cmd,num)
|
|
}
|
|
);
|
|
}},
|
|
{ view:"button", type:"icon", icon:"times-circle", tooltip:'Kill Agent', width:30, click:async function () {
|
|
var tree = UI('treeAgentsNode'+num);
|
|
var selectedId = tree.getSelectedId();
|
|
if (selectedId.indexOf('agent.')==0) {
|
|
var agentid = selectedId.substring(selectedId.indexOf('.')+1,selectedId.indexOf(' '));
|
|
await cmd.kill(agentid);
|
|
}
|
|
if (options.infoView) UI('infoShellWinScrollView'+num).removeView(options.infoView);
|
|
options.infoView=UI('infoShellWinScrollView'+num).addView(
|
|
{
|
|
rows : await updateInfo(cmd,num)
|
|
}
|
|
);
|
|
}},
|
|
{ view:"label", label:"Info / "+Label(), id:'infoShellWinLabel'+num, align:'right'},
|
|
{ view:"button", type:"icon", icon:"check-square", align:'center', width:30, click: function () {
|
|
infoShellWin[num].hide();
|
|
}}
|
|
]
|
|
},
|
|
body:{
|
|
view : 'form',
|
|
scroll : 'y',
|
|
height: 300,
|
|
id:'infoShellWinScrollView'+num,
|
|
rows : [
|
|
]
|
|
}
|
|
});
|
|
|
|
}
|
|
createShell(shellNum,{});
|
|
shellNum++;
|
|
|
|
|
|
|
|
|
|
/************ EDITOR *****************/
|
|
|
|
function createEditor(num,opts) {
|
|
var options = {
|
|
arguments : "{}",
|
|
level:2,
|
|
compiled:false,
|
|
file:'untitled',
|
|
shell:opts.shell, // number
|
|
script:opts.script,
|
|
name : opts.name
|
|
}
|
|
function Label() {
|
|
if (options.script)
|
|
return options.file+' / script / Shell '+options.shell+' / Editor '+num
|
|
else
|
|
return options.file+' / '+options.name+" / Shell "+options.shell+" / Editor "+num
|
|
}
|
|
var head = {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"button", type:"icon", icon:"folder-open", tooltip:'Open File', width:30, click:function () {
|
|
options.compiled = false;
|
|
loadFile(function (text,file) {
|
|
if (text) {
|
|
UI('SourceText'+num).setValue(text)
|
|
options.file=file
|
|
UI('SourceTextWinLabel'+num).setValue(Label())
|
|
updateMenu();
|
|
}
|
|
});
|
|
}},
|
|
{ view:"button", type:"icon", icon:"save", tooltip:'Save File', width:30, click:function () {
|
|
var code = UI('SourceText'+num).getValue();
|
|
if (!/\.js$/.test(options.file)) options.file+='.js';
|
|
saveFile(code,options.file,'text/plain',function (file) {
|
|
if (file) {
|
|
options.file=file
|
|
UI('SourceTextWinLabel'+num).setValue(Label())
|
|
updateMenu()
|
|
}
|
|
});
|
|
}},
|
|
{ view:"button", type:"icon", icon:"file", tooltip:'New File', width:30, click:function () {
|
|
options.compiled = false;
|
|
}},
|
|
opts.script?null:{ view:"button", type:"icon", icon:"navicon", tooltip:'Config', width:30, click:function () {
|
|
configEditorWin[num].show();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"user", tooltip:'Share Code', width:30, click:function () {
|
|
Clip.share(num);
|
|
}},
|
|
opts.script?null:{ view:"button", type:"icon", icon:"indent", tooltip:'Compile Class', width:30, click:function () {
|
|
var code = UI('SourceText'+num).getValue();
|
|
var acname = shell[options.shell].options.shell.env.compile(code);
|
|
if (acname) {
|
|
options.file = acname+'.js';
|
|
UI('SourceTextWinLabel'+num).setValue(Label());
|
|
options.compiled = true;
|
|
}
|
|
updateMenu();
|
|
}},
|
|
opts.script?{ view:"button", type:"icon", icon:"play", tooltip:'Execute script', width:30, click:function () {
|
|
var code = 'later(1,function () {'+UI('SourceText'+num).getValue()+'})';
|
|
shell[options.shell].ask(code);
|
|
}}
|
|
:{ view:"button", type:"icon", icon:"play", tooltip:'Create Agent', width:30, click:function () {
|
|
if (options.compiled == false) {
|
|
var code = UI('SourceText'+num).getValue();
|
|
var acname = shell[options.shell].options.shell.env.compile(code);
|
|
if (acname) {
|
|
options.file = acname+'.js';
|
|
UI('SourceTextWinLabel'+num).setValue(Label());
|
|
}
|
|
options.compiled = true;
|
|
updateMenu();
|
|
}
|
|
var ac=options.file.replace(/\.js$/,''),args;
|
|
if (options.arguments!="") eval('args='+options.arguments);
|
|
else args={};
|
|
var id=shell[options.shell].options.shell.env.create(ac,args,options.level);
|
|
if (id) {
|
|
info('Agent '+id+' of class '+ac+' started.');
|
|
shell[options.shell].print('[JLB] Agent '+id+' of class '+ac+' started.');
|
|
} else {
|
|
error('Starting agent of class '+ac+' failed.');
|
|
shell[options.shell].print('[JLB] Error: Starting agent of class '+ac+' failed.');
|
|
}
|
|
}},
|
|
{ view:"label", label:Label(), id:'SourceTextWinLabel'+num, align:'right'},
|
|
{ view:"button", type:"icon", icon:"close", tooltip:'Close Editor', width:30, click:function () {
|
|
var self=editorWin[num];
|
|
// editorWin[num]=undefined;
|
|
self.hide();
|
|
}},
|
|
].filter(function (o) { return o })
|
|
}
|
|
var config = {
|
|
id:'SourceTextWin'+num,
|
|
view:"window",
|
|
height:350,
|
|
width:600,
|
|
left:250, top:50,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:opts.script?'blue_toolbar':'green_toolbar',
|
|
head:head,
|
|
body:{
|
|
id : 'SourceText'+num,
|
|
view: "codemirror-editor",
|
|
attributes : { spellcheck:false, smartIndent:false, indentUnit:2},
|
|
}
|
|
}
|
|
|
|
editorWin[num]=webix.ui(config);
|
|
if (!options.script) UI('SourceText'+num).setValue(classTemplate);
|
|
|
|
editorWin[num]._options=options;
|
|
editorWin[num].show();
|
|
|
|
/********** EDITOR CONFIG ****************/
|
|
configEditorWin[num]=webix.ui({
|
|
id:'configEditorWin'+num,
|
|
view:"window",
|
|
width:300,
|
|
height:450,
|
|
left:90, top:90,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'gray_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"label", label:"Configuration", align:'right'},
|
|
{ view:"button", type:"icon", icon:"check-square", align:'center', width:30, click: function () {
|
|
options.arguments = UI('configEditorAgentArgs'+num).getValue();
|
|
options.level = Number(UI('configEditorAgentLevel'+num).getValue())||0;
|
|
options.file=UI('configEditorFileName'+num).getValue();
|
|
UI('SourceTextWinLabel'+num).setValue(Label());
|
|
configEditorWin[num].hide();
|
|
}}
|
|
]
|
|
},
|
|
body: {
|
|
rows:[
|
|
{ view:"form", scroll:true, width:300, height:400, elements: [
|
|
|
|
{ view:"label", label:"<b>Agent Creation</b>", height:'18px', align:'left'},
|
|
{ view:"textarea", id:"configEditorAgentArgs"+num, label:"Argument", height:150, value:options.arguments},
|
|
{ view:"text", id:"configEditorAgentLevel"+num, label:"Level", value:options.level},
|
|
{ view:"label", label:"<b>Code</b>", height:'18px', align:'left'},
|
|
{ view:"text", id:"configEditorFileName"+num, label:"File Name", value:options.file},
|
|
]}
|
|
]
|
|
}
|
|
});
|
|
updateMenu();
|
|
}
|
|
|
|
|
|
|
|
/****************** MONITOR *******************/
|
|
|
|
function createMonitor(num,opts) {
|
|
var tables={},reporter;
|
|
opts.cmd = function (cmd) {
|
|
// @cmd arg1 arg2 ...
|
|
var obj,table,
|
|
prefix=cmd.substr(0,cmd.indexOf(' ')),
|
|
args=cmd.substr(cmd.indexOf(' ')+1);
|
|
console.log(prefix);
|
|
console.log(args);
|
|
switch (prefix) {
|
|
case '@monitor:new':
|
|
obj=JSON.parse(args);
|
|
options.header=obj.header;
|
|
options.id=obj.id;
|
|
if (!reporterWin[num]) createReporter(num,options);
|
|
break;
|
|
case '@monitor:data':
|
|
if (!reporterWin[num]) return;
|
|
obj=JSON.parse(args);
|
|
table=UI(reporterWin[num]._datatable.id);
|
|
table.add(obj.row)
|
|
break;
|
|
}
|
|
}
|
|
monitor[num] = winShell(opts);
|
|
var options = monitor[num].options;
|
|
options.shell = opts.shell;
|
|
options.closed = false;
|
|
|
|
function Label () {
|
|
return jamConfig.name+" / Shell "+num+" / Agent Monitor"
|
|
}
|
|
monitorWin[num]=webix.ui({
|
|
id:'MonitorWin'+num,
|
|
view:"window",
|
|
height:350,
|
|
width:600,
|
|
left:350, top:250,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'black_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"button", type:"icon", icon:"eraser", tooltip:'Clear', width:30, click:function () {
|
|
monitor[num].commands.clear()
|
|
}},
|
|
{ view:"button", type:"icon", icon:"dot-circle-o", tooltip:'Scroll Auto', id:'MonitorWinLogFilmBut'+num, width:30, click:function () {
|
|
UI('MonitorWinLog'+num).scrollAuto=!UI('MonitorWinLog'+num).scrollAuto;
|
|
if (UI('MonitorWinLog'+num).scrollAuto) UI('MonitorWinLogFilmBut'+num).define('icon','arrow-circle-down')
|
|
else UI('MonitorWinLogFilmBut'+num).define('icon','dot-circle-o');
|
|
UI('MonitorWinLogFilmBut'+num).refresh();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"table", tooltip:'Data Monitor', width:30, click:function () {
|
|
if (!reporterWin[num]) return;
|
|
// createReporter(num,options);
|
|
reporterWin[num].show();
|
|
}},
|
|
{ view:"label", label:Label(), id:'MonitorWinLabel'+num, align:'right'},
|
|
{ view:"button", type:"icon", icon:"close", tooltip:'Kill', width:30, click:function () {
|
|
monitorWin[num].hide();
|
|
}},
|
|
]
|
|
},
|
|
body:{
|
|
id : 'MonitorWinLog'+num,
|
|
view : 'scrollview',
|
|
scroll : 'y',
|
|
body : {
|
|
id:'MonitorWinLogText'+num,
|
|
rows : [
|
|
{template:('<div id="MonitorWinOutput'+num+'" '+
|
|
'spellcheck="false" style="">'), height:"auto", borderless:true},
|
|
]
|
|
}
|
|
}
|
|
});
|
|
UI('MonitorWinLog'+num).scrollAuto=false;
|
|
monitorWin[num].show();
|
|
monitor[num].init(undefined,"MonitorWinOutput"+num,UI('MonitorWinLog'+num));
|
|
UI('MonitorWinLabel'+num).setValue(Label());
|
|
updateMenu()
|
|
}
|
|
|
|
/****************** REPORTER *******************/
|
|
|
|
function createReporter(num,options) {
|
|
function makeReport(tbl) {
|
|
console.log(tbl)
|
|
var header = tbl.shift(),
|
|
columns = [],
|
|
hash =[],
|
|
data =[];
|
|
header.forEach(function (col,i) {
|
|
console.log(i,col)
|
|
columns.push({id:col,header:col,editor:'text'}); hash[i]=col;
|
|
});
|
|
tbl.forEach (function (row,i) {
|
|
var obj={id:i};
|
|
row.forEach(function (col,j) { obj[hash[j]]=col; });
|
|
data.push(obj);
|
|
});
|
|
var datatbl = {
|
|
view:"datatable",
|
|
id:'DataTable'+options.id+num,
|
|
columns:columns,
|
|
select:"cell",
|
|
multiselect:true,
|
|
blockselect:true,
|
|
clipboard:"selection",
|
|
data: data,
|
|
on:{
|
|
onBeforeBlockSelect:function(start, end, fin){
|
|
if (start.column === "rank")
|
|
end.column = "votes";
|
|
|
|
if (fin && start.column == "rank"){
|
|
var mode = this.isSelected(start) ? -1 : 1;
|
|
this.selectRange(
|
|
start.row, start.column, end.row, end.column,
|
|
mode
|
|
);
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
};
|
|
return datatbl;
|
|
}
|
|
var datatable = makeReport([options.header.map(function (col) { return Object.keys(col)[0]})]);
|
|
reporterWin[num]=webix.ui({
|
|
id:'ReporterWin'+num,
|
|
view:"window",
|
|
height:350,
|
|
width:600,
|
|
left:350, top:250,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
head: {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"button", type:"icon", icon:"eraser", tooltip:'Clear', width:30, click:function () {
|
|
}},
|
|
{ view:"button", type:"icon", icon:"flag", tooltip:'Scroll Auto', id:'ReporterWinLogFilmBut'+num, width:30, click:function () {
|
|
UI('ReporterWinLog'+num).scrollAuto=!UI('ReporterWinLog'+num).scrollAuto;
|
|
if (UI('ReporterWinLog'+num).scrollAuto) UI('ReporterWinLogFilmBut'+num).define('icon','flag-o')
|
|
else UI('ReporterWinLogFilmBut'+num).define('icon','flag');
|
|
UI('ReporterWinLogFilmBut'+num).refresh();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"table", tooltip:'Data Monitor', width:30, click:function () {
|
|
}},
|
|
{ view:"label", label:"Thread "+options.thread+ " / "+options.ip+':'+options.port+" / Shell "+options.shell+" / Report "+num, id:'ReporterWinLabel'+num, align:'right'},
|
|
{ view:"button", type:"icon", icon:"close", tooltip:'Kill', width:30, click:function () {
|
|
var self=reporterWin[num];
|
|
self.hide();
|
|
}},
|
|
]
|
|
},
|
|
body:datatable
|
|
|
|
});
|
|
reporterWin[num]._datatable=datatable;
|
|
return reporterWin[num]
|
|
}
|
|
|
|
/* Load help files */
|
|
help.aios = SHELL.doc.aios;
|
|
help.jamsh = SHELL.doc.shell;
|
|
help.js = SHELL.doc.javascript;
|
|
|
|
/////////////
|
|
// CHAT WIN
|
|
/////////////
|
|
chatWin = webix.ui({
|
|
id:'chatWin',
|
|
view:"window",
|
|
height:400,
|
|
width:400,
|
|
left:100, top:100,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
head: {
|
|
view:"toolbar",
|
|
id:"myToolbarchatWin",
|
|
cols:[
|
|
{ view:"button", type:"icon", icon:"eraser", tooltip:'Clear', width:50, click:function () {
|
|
chatReset();
|
|
}},
|
|
{ view:"button", type:"icon", icon:"user", tooltip:'Talk', width:50, click:function () {
|
|
// interrupt request (question)
|
|
}},
|
|
{ view:"label", label:"Agent Chat", align:'right'},
|
|
{ view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () {
|
|
chatWin.hide();
|
|
}}
|
|
]
|
|
},
|
|
body:{
|
|
template : ' <div class="botui-app-container" id="chat-bot" style="width:100%;"><bot-ui></bot-ui></div>',
|
|
borderless:false
|
|
}
|
|
});
|
|
|
|
chatWin.chatActions=[]; // copy(chatActionsInit,true);
|
|
chatWin.chatLastAction=undefined;
|
|
chatWin.nextChatHistory=[];
|
|
chatWin.chatHistory=[];
|
|
chatWin.chatOpen=false;
|
|
|
|
// Clear the chat
|
|
function chatReset () {
|
|
chatWin.chatActions=[];
|
|
chatWin.chatHistory=[];
|
|
chatWin.nextChatHistory=[];
|
|
chatWin.chatLastAction=undefined;
|
|
if (chatWin.botui) {
|
|
chatWin.botui.message.removeAll();
|
|
}
|
|
chatRefresh();
|
|
}
|
|
// Refresh the chat by adding old/new messages and actions
|
|
|
|
function chatRefresh () {
|
|
if (!chatWin.botui) return;
|
|
function exec(l,last) {
|
|
var todo=l.shift();
|
|
if (!todo) return;
|
|
function doit(todo,last) {
|
|
switch (todo.kind) {
|
|
case 'message':
|
|
last=chatWin.botui.message.bot(todo);
|
|
break;
|
|
case 'answer':
|
|
last=chatWin.botui.message.human(todo);
|
|
break;
|
|
case 'wait':
|
|
if (last) last=last.then(function () {});
|
|
break;
|
|
case 'button':
|
|
chatWin.chatLastAction=[todo];
|
|
if (last) last=last.then(function () { return chatWin.botui.action.button(todo); }).then(function (res) {
|
|
chatWin.chatLastAction=[];
|
|
return { then:function (f) { f(res) } }
|
|
});
|
|
else {
|
|
last=chatWin.botui.action.button(todo).then(function (res) {
|
|
chatWin.chatLastAction=undefined;
|
|
return { then:function (f) { f(res) } }
|
|
});
|
|
}
|
|
break;
|
|
case 'value':
|
|
chatWin.chatLastAction=[todo];
|
|
if (last) last=last.then(function () { return chatWin.botui.action.text(todo); }).then(function (res) {
|
|
chatWin.chatLastAction=[];
|
|
return { then:function (f) { f(res) } }
|
|
});
|
|
else {
|
|
last=chatWin.botui.action.text(todo).then(function (res) {
|
|
chatWin.chatLastAction=undefined;
|
|
return { then:function (f) { f(res) } }
|
|
});
|
|
}
|
|
break;
|
|
case 'checkpoint':
|
|
if (chatWin.chatLastAction.length) chatWin.chatLastAction.push(todo);
|
|
if (last) last=last.then(function (res) { if (todo.timer) clearTimeout(todo.timer); return todo.callback(res) });
|
|
break;
|
|
}
|
|
return last
|
|
}
|
|
last=doit(todo,last);
|
|
if (l.length) exec(l,last);
|
|
}
|
|
exec(chatWin.chatHistory);
|
|
exec(chatWin.chatActions);
|
|
}
|
|
// Add a chat action
|
|
function chatAction (action) {
|
|
chatWin.chatActions.push(action);
|
|
}
|
|
|
|
// External chat requests
|
|
function chatQuestion (id, question, action, callback, timeout) {
|
|
// TODO: Remove question after timeout!
|
|
var actions=[],timer;
|
|
chatAction({kind:'message', delay:0, content: id+': '+question });
|
|
if (timeout) timer=setTimeout(function () {
|
|
chatWin.chatLastAction=[];
|
|
// console.log('chatQuestion timeout');
|
|
chatWin.chatActions=chatWin.chatActions.filter(function (todo) {
|
|
if (todo.kind=='checkpoint' || todo.action) return false;
|
|
else return true;
|
|
});
|
|
if (chatWin.botui) chatWin.botui.removeAction();
|
|
if (callback) callback();
|
|
},timeout);
|
|
if (action instanceof Array) {
|
|
// Buttons/Choices
|
|
if (typeof action[0] == 'string') action=action.map(function (s) { return { text:s, value:s } });
|
|
chatAction({kind:'button', delay:0, action: action});
|
|
chatAction({kind:'checkpoint', callback:callback, timer:timer});
|
|
} else if (typeof action == 'object') {
|
|
// Value or text
|
|
chatAction({kind:'value', delay:0, action: action});
|
|
chatAction({kind:'checkpoint', callback:callback, timer:timer});
|
|
}
|
|
chatRefresh();
|
|
}
|
|
|
|
function chatMessage (id,message) {
|
|
chatAction({kind:'message', delay:0, content: id+': '+message });
|
|
chatRefresh();
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Chat Script Interpreter */
|
|
// {question:string, choices?:[], value?:number|string, eval?:function,
|
|
// cond?:function, timeout?:numebr, tag?:string }
|
|
// {message:string}
|
|
// {finalize:function}
|
|
// {process:function}
|
|
// {init:function}
|
|
// ! After reply to a question the question record contains an answer attribute !
|
|
chatScript = {
|
|
script : [],
|
|
id:'Anonymous',
|
|
index : 0,
|
|
cancel : function () {
|
|
self.chatScript.script=[];
|
|
},
|
|
init: function (id,script) {
|
|
self.chatScript.script=script;
|
|
self.chatScript.index=0;
|
|
self.chatScript.id=id;
|
|
},
|
|
next : function () {
|
|
var process = shell[1].run.Aios.current.process;
|
|
var next = self.chatScript.script[self.chatScript.index];
|
|
self.chatScript.index++;
|
|
if (!next) return 0;
|
|
if (next.question) {
|
|
if (next.cond && !next.cond.call(process.agent,self.chatScript.script)) return -1;
|
|
if (next.eval) {
|
|
var replace = next.eval.call(process.agent,self.chatScript.script);
|
|
// TODO
|
|
}
|
|
var timeout = next.timeout||30000;
|
|
chatQuestion(self.chatScript.id,
|
|
next.question,
|
|
next.choices||{value:next.value},
|
|
function (res) {
|
|
if (next.callback)
|
|
shell[1].run.Aios.CB(process,next.callback,res?[res.value]:null);
|
|
process.wakeup();
|
|
shell[1].run.schedule();
|
|
},
|
|
timeout
|
|
);
|
|
process.suspend(shell[1].run.Aios.timeout(timeout));
|
|
} else if (next.message) {
|
|
chatMessage(self.chatScript.id,
|
|
next.message)
|
|
}
|
|
else if (next.process) next.process(self.chatScript.script);
|
|
else if (next.init) next.init.call(process.agent,self.chatScript.script);
|
|
else if (next.finalize) next.finalize(self.chatScript.script);
|
|
return 1;
|
|
},
|
|
reset : function () {
|
|
self.chatScript.index=0;
|
|
},
|
|
}
|
|
|
|
chatInit = function () {
|
|
if (!chatWin.botui) {
|
|
chatWin.nextChatHistory=[];
|
|
chatWin.botui = new BotUI('chat-bot',{callback:function (msg) {
|
|
// Record message history for page refresh
|
|
if (msg.content) {
|
|
if (msg.human) chatWin.nextChatHistory.push({kind:"answer", delay:0, content:msg.content});
|
|
else chatWin.nextChatHistory.push({kind:"message", delay:0, content:msg.content});
|
|
}
|
|
}});
|
|
chatMessage('Chat','Ready.');
|
|
chatRefresh();
|
|
}
|
|
}
|
|
chatAgent = function (action) {
|
|
if (!chatWin.agent) {
|
|
if (action.load)
|
|
return clippy.load(action.load, function (agent) {
|
|
chatWin.agent=agent;
|
|
});
|
|
else return;
|
|
}
|
|
for(var p in action) {
|
|
switch (p) {
|
|
case 'play' : chatWin.agent.play(action[p]); break;
|
|
case 'speak': chatWin.agent.speak(action[p]); break;
|
|
case 'hide': chatWin.agent.stop(); chatWin.agent.hide(); break;
|
|
case 'moveTo': chatWin.agent.moveTo(action[p].x,action[p].y,action[p].time); break;
|
|
case 'load': chatWin.agent.show(true); break;
|
|
case 'show': chatWin.agent.show(action[p]); break;
|
|
case 'stop': chatWin.agent.stop(); break;
|
|
case 'stopCurrent': chatWin.agent.stopCurrent(); break;
|
|
}
|
|
}
|
|
}
|
|
shell[1].run.extend([2,3],'message',chatMessage,2);
|
|
shell[1].run.extend([2,3],'question',function (id, question, action, callback, timeout) {
|
|
var process = shell[1].run.Aios.current.process;
|
|
if (timeout==undefined) timeout=60000;
|
|
chatQuestion (id, question, action, function (res) {
|
|
shell[1].run.Aios.CB(process,callback,res?[res.value]:null);
|
|
process.wakeup();
|
|
shell[1].run.schedule();
|
|
},timeout);
|
|
process.suspend(shell[1].run.Aios.timeout(timeout));
|
|
},[4,5]);
|
|
|
|
|
|
function openWin(num,content,options) {
|
|
var panel = webix.ui({
|
|
id:'Panel'+num,
|
|
view:"window",
|
|
height:350,
|
|
width:600,
|
|
left:350, top:250,
|
|
move:true,
|
|
resize: true,
|
|
toFront:true,
|
|
css:'black_toolbar',
|
|
head: {
|
|
view:"toolbar",
|
|
cols:[
|
|
{ view:"label", label:options.title||("Window "+num), align:'right'},
|
|
{ view:"button", type:"icon", icon:"close", tooltip:'Close', width:30, click:function () {
|
|
panel.close();
|
|
}},
|
|
]
|
|
},
|
|
body: {
|
|
template : content,
|
|
borderless:false
|
|
}
|
|
});
|
|
panel.show();
|
|
}
|
|
|
|
Config=jamConfig;
|
|
//////////////////////////////////////////////////////////////
|
|
|