///////////////////////////////////////////////////////////////////////////////
/*
build.js
COPYRIGHT
---------
Copyright (C) 2014-2023 Mark G.Daniel
This program, comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it under the
conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version.
http://www.gnu.org/licenses/gpl.txt
VERSION
-------
20-MAR-2018 MGD mdsiQueryConfig()
18-APR-2015 MGD bugfix; mdsiConfigUrl() protocol and host and munge '+'
05-FEB-2014 MGD initial
*/
///////////////////////////////////////////////////////////////////////////////
var mdsi_AlertsDisplay = false,
mdsi_ClusterDisplay = false,
mdsi_CollectDisplay = false,
mdsi_DiskDisplay = false,
mdsi_DiskDeltaDisplay = false,
mdsi_DiskQlenDisplay = false,
mdsi_HistoryDisplay = false,
mdsi_HistoryMinutes = 5,
mdsi_HistoryHeight2 = 1,
mdsi_ModesDisplay = false,
mdsi_InsightDisplay = false,
mdsi_OpcomAudit = false,
mdsi_OpcomDisplay = false,
mdsi_PerHistoryDisplay = false,
mdsi_PerProcessPid = 0,
mdsi_PrevPerProcessPid = 0,
mdsi_ProcessDisplay = false,
mdsi_SynopsisDisplay = false,
mdsi_TipsDisplay = false,
mdsi_UpdateDisplay = false;
var mdsi_ThisFrame;
///////////////////////////////////////////////////////////////////////////////
/*
The stand-alone flag is set from a query string element.
*/
function mdsiBuildPage ()
{
if (mdsiFromQuery('frame'))
{
/* an iframe (contained by the parent page) */
if (acme_StandAlone)
{
mdsiCSS ('#configAnchor','color','#000000');
mdsiCSS ('#configControl','color','#000000');
mdsiCSS ('body','background','transparent');
mdsiCSS ('#monitor','background','transparent');
mdsiCSS ('#monitor','border','none');
// mdsiCSS ('#monitor','border','dotted 1px silver');
mdsiCSS ('#monitor','box-shadow','none');
mdsiCSS ('#monitor','padding','5px 15px 0 10px');
}
else
{
mdsiCSS ('#configAnchor','color','#ffffff');
mdsiCSS ('#configControl','color','#ffffff');
mdsiCSS ('body','background','transparent');
mdsiCSS ('#configAnchor','color','#ffffff');
mdsiCSS ('#configControl','color','#ffffff');
mdsiCSS ('#monitor','border','1px outset white');
mdsiCSS ('#monitor','box-shadow','1px 3px 5px 1px #505050');
mdsiCSS ('#monitor','padding','10px');
}
}
else
{
/* the fundamental parent page (contains the iframes) */
if (acme_StandAlone)
{
mdsiCSS ('#configTitle','color','#ffffff');
mdsiCSS ('#configTitle','text-shadow',
'0 1px 0 #ccc,\
0 2px 0 #c9c9c9,\
0 3px 0 #bbb,\
0 4px 0 #b9b9b9,\
0 5px 0 #aaa,\
0 6px 1px rgba(0,0,0,.1),\
0 0 5px rgba(0,0,0,.1),\
0 1px 3px rgba(0,0,0,.3),\
0 3px 5px rgba(0,0,0,.2),\
0 5px 10px rgba(0,0,0,.25),\
0 10px 10px rgba(0,0,0,.2),\
0 20px 20px rgba(0,0,0,.15)');
mdsiCSS ('#configTitle','background-clip','text');
/** http://www.colorzilla.com/gradient-editor/ **/
mdsiCSS ('body','background','#eeeeee');
mdsiCSS ('body','background',
'linear-gradient(135deg, #eeeeee 50%,#b8b8b8 100%)');
}
else
{
mdsiCSS ('#configTitle','background-clip','text');
mdsiCSS ('#configTitle','text-shadow',
'0px 1px 2px rgba(255,255,255,.4), -1px -2px 0px rgba(0,0,0,.7)');
/** http://www.colorzilla.com/gradient-editor/ **/
mdsiCSS ('body','background','#b5bdc8;');
mdsiCSS ('body','background',
'linear-gradient(135deg, #b5bdc8 0%,#929ca5 50%,#48545b 100%);');
}
mdsiCSS ('body','background-attachment','fixed');
}
window.addEventListener('message', acmePostedMessage, false);
if (mdsiFromQuery('frame'))
acmeLoadFile('monitor.html',mdsiBuildMonitor);
else
mdsiBuildMonDeSi();
}
///////////////////////////////////////////////////////////////////////////////
/*
Set runtime configuration from request query and/or MONDESI_QUERY string
elements.
*/
function mdsiQueryConfig ()
{
if (!mdsi_StaticData) return setTimeout(mdsiQueryConfig,100);
var yep = /^(x|X|1)$/;
var value;
if (value = mdsiFromQuery('alerts')) mdsiAlertsClick(value.match(yep));
if (value = mdsiFromQuery('audit'))
if (value.match(yep))
$byId('checkboxAudit').checked = true;
if (value = mdsiFromQuery('cluster')) mdsiClusterClick(value.match(yep));
if (value = mdsiFromQuery('collect')) mdsiCollectClick(value.match(yep));
if (value = mdsiFromQuery('disk')) mdsiDiskClick(value.match(yep));
if (value = mdsiFromQuery('delta')) mdsiDiskDeltaClick(value.match(yep));
if (value = mdsiFromQuery('history')) mdsiHistoryClick(value.match(yep));
if (value = mdsiFromQuery('height'))
{
if (value == '1') mdsiHeight2Click(1);
if (value == '2') mdsiHeight2Click(2);
}
if (value = mdsiFromQuery('minutes'))
{
if (value == '5') mdsiMinutesClick(5);
if (value == '15') mdsiMinutesClick(15);
}
if (value = mdsiFromQuery('modes'))
if (value.match(yep))
$byId('checkboxModes').checked = true;
if (value = mdsiFromQuery('opcom'))
if (value.match(yep))
$byId('checkboxOpcom').checked = true;
if (value = mdsiFromQuery('process')) mdsiProcessClick(value.match(yep));
if (value = mdsiFromQuery('queue')) mdsiDiskQlenClick(value.match(yep));
if (value = mdsiFromQuery('tips')) mdsiTipsClick(value.match(yep));
if (value = mdsiFromQuery('update')) mdsiUpdateClick(value.match(yep));
}
///////////////////////////////////////////////////////////////////////////////
/*
Building the top-level main page. Generate an iframe for each server to be
monitored. When the iframe loads it calls acmeBuildIframeLoad() to check the
load success (or otherwise).
*/
function mdsiBuildMonDeSi ()
{
// Opera (only?) wait for the document to materialise
if (!document.body)
{
setTimeout('mdsiBuildMonDeSi()',250);
return;
}
var nodes;
if (!(nodes = mdsiFromQuery('nodes')))
nodes = location.protocol + '//' + location.host + location.pathname;
nodes = nodes.replace(/\n|\r\n|\r/g,'+');
nodes = nodes.replace(/\+{2,}/g,'+');
nodes = nodes.replace(/^\+/, '');
nodes = nodes.replace(/^\+$/, '');
var these = nodes.split('+');
var html = '
\
\
\
\
\
\
\
MonDeSi
\
\
';
if (idx > 1)
html += '
\
\
\
';
html += '
\
';
for (var idx = 0; idx < these.length; idx++)
{
if (!these[idx].length) continue;
var parts = these[idx].split('?');
these[idx] = parts[0] + '?frame=' + (idx+1)
if (location.search.substr(1).length)
these[idx] += '&' + location.search.substr(1);
if (acme_StandAlone) these[idx] += '&salone=1';
if (parts.length > 1) these[idx] += '&' + parts[1];
acmeIframeCheck(idx+1,these[idx]);
html += '';
}
html += '
';
document.body.innerHTML = html;
}
///////////////////////////////////////////////////////////////////////////////
/*
Send a message to each frame to open/close their WebSocket connection. Can be
done semi-directly because the configuration panel resides in the top-level
page.
*/
function mdsiConfigCollectClick (checked)
{
if (typeof checked == 'undefined')
checked = $byId('checkboxConfigCollect').checked;
for (var cnt = 0; true; cnt++)
{
if (!(obj = $byId('FRAME'+(cnt+1)))) break;
var json = '{"$ConfigCollect":true,"checked":' + checked + '}';
obj.contentWindow.postMessage(json,'*');
}
}
///////////////////////////////////////////////////////////////////////////////
/*
Build the monitor page in an iframe.
*/
function mdsiBuildMonitor (html)
{
// tell the parent the frame has loaded successfully
acmeIframeCheck(true);
mdsi_ThisFrame = 'FRAME' + acmeFrameNumber();
var body = document.getElementsByTagName('body')[0];
body.innerHTML = html;
mdsiBuildControl();
mdsiBuildDisk();
mdsiSetHistoryWidth(mdsi_HistWidth5);
mdsiCollectClick(true);
mdsiUpdateClick(true);
mdsiAlertsClick(true);
mdsiModesClick(false);
mdsiPerHistoryClick(false);
mdsiHeight2Click(1);
mdsiMinutesClick(5);
mdsiQueryConfig();
acmeAdjustSize();
acmeLoadFile('tips.js','mdsiToolTipInit()');
}
///////////////////////////////////////////////////////////////////////////////
/*
*/
function mdsiConfigClick ()
{
var ticked = $byId('SECTION1');
if (ticked.style.display == 'none')
ticked.style.display = 'block'
else
ticked.style.display = 'none'
if (acme_StandAlone) acmeFitWindow();
}
///////////////////////////////////////////////////////////////////////////////
/*
*/
function mdsiMonitorClick (obj)
{
var closed = $byId('monitorClosed');
var open = $byId('monitorOpen');
if (obj.checked)
{
closed.style.display = 'none';
open.style.display = 'block';
mdsi_SynopsisDisplay = false;
}
else
{
closed.style.display = 'block';
open.style.display = 'none';
mdsi_SynopsisDisplay = true;
$byId('closedAlert').innerHTML = '';
mdsiDisplaySynopsis();
}
acmeAdjustSize();
}
///////////////////////////////////////////////////////////////////////////////
/*
Generate the URL, including the query string, used to open the top-level
monitor page.
*/
function mdsiConfigUrl ()
{
var action = location.protocol + '//' + location.host + $ScriptName;
var nodes = $byId('configNodes').value;
nodes = nodes.replace(/\n|\r\n|\r/g,'+');
nodes = nodes.replace(/\+{2,}/g,'+');
nodes = nodes.replace(/^\+/, '');
nodes = nodes.replace(/^\+$/, '');
var url = action + '?nodes=' + encodeURIComponent(nodes);
return url;
}
///////////////////////////////////////////////////////////////////////////////
/*
Open a standalone monitor.
*/
function mdsiOpenMonDeSi (url)
{
if (url)
window.onerror = function (msg,url,lnum) { alert (msg+' '+url+' '+lnum) };
else
{
if (!document.getElementById('configForm'))
{
alert(mdsLangBookmarklet);
return false;
}
}
var name = new Date();
name = 'mondesi_' + name.getTime();
var specs = 'toolbar=0,location=0,directories=0,status=0,' +
'menubar=0,scrollbars=1,resizable=0,copyhistory=0,' +
'width=100,height=100';
window.open((url?url:mdsiConfigUrl()),name,specs);
return false;
}
///////////////////////////////////////////////////////////////////////////////
/*
Display a link capable of being put into a bookmark and used to directly open a
standalone monitor.
*/
function mdsiLinkClick (change)
{
var cl = document.getElementById('configLink');
if (!change)
{
if (cl.style.display == 'inline-block')
{
cl.style.display = 'none';
return false;
}
cl.style.display = 'inline-block';
}
if (cl.style.display != 'inline-block') return false;
var params = 'status=0,toolbar=0,location=0,menubar=0,resizable=0,' +
'scrollbars=1,height=100,width=100';
var href = 'javascript:void(window.open("' + mdsiConfigUrl() +
'&salone=1' + '","_blank","' + params + '"))';
var title = 'MonDeSi ' + $ExeVersion;
var nodes = $byId('configNodes').value;
if (nodes.length < 10)
cl.style.display = 'none';
else
{
var ca = $byId('configAnchor');
ca.href = ca.innerHTML = href;
cl.style.display = 'inline-block';
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
////////////////////////
// control checkboxes //
////////////////////////
///////////////////////////////////////////////////////////////////////////////
/*
Generate the monitor control check boxes.
*/
function mdsiBuildControl ()
{
var html = '';
html += '
';
html += '
\
';
html += '
\
';
html += '
\
';
html += '
\
';
html += '
\
';
html += '
\
';
html += '
\
';
html += '
\
\
\
';
html += '
';
html += '
\
';
html += '
\
';
html += '
\
\
\
\
\
\
';
html += '
\
';
html += '
\
';
html += '
\
';
html += '
';
$byId('control').innerHTML = html;
}
///////////////////////////////////////////////////////////////////////////////
/*
Collect checkbox has been clicked.
The dollar prefixed version is called from acmePostedMessage().
*/
function $CollectClick (state) { mdsiCollectClick(state) };
function mdsiCollectClick (state)
{
var cbx = $byId('checkboxCollect');
if (typeof state == 'undefined') state = !mdsi_CollectDisplay;
mdsi_CollectDisplay = cbx.checked = state;
mdsiStreamData(state);
if (state) mdsi_CollectStartTime = new Date();
}
///////////////////////////////////////////////////////////////////////////////
/*
Tips checkbox has been clicked.
*/
function mdsiTipsClick (state)
{
var cbx = $byId('checkboxTips');
if (typeof state == 'undefined') state = !mdsi_TipsDisplay;
mdsi_TipsDisplay = cbx.checked = state;
}
///////////////////////////////////////////////////////////////////////////////
/*
Update checkbox has been clicked.
*/
function mdsiUpdateClick (state)
{
var cbx = $byId('checkboxUpdate');
if (typeof state == 'undefined') state = !mdsi_UpdateDisplay;
mdsi_UpdateDisplay = cbx.checked = state;
}
///////////////////////////////////////////////////////////////////////////////
/*
History checkbox has been clicked.
*/
function mdsiHistoryClick (state)
{
var cbx = $byId('checkboxHistory');
var htab = $byId('historyDiv');
if (typeof state == 'undefined') state = !mdsi_HistoryDisplay;
mdsi_HistoryDisplay = cbx.checked = state;
htab.style.display = state ? 'block' : 'none';
acmeAdjustSize();
}
///////////////////////////////////////////////////////////////////////////////
/*
The collection/display checkbox has been clicked from 5->15 or 15->5.
The number of seconds to store the data is bumped in the 5->15 transition but
not reset with the 15->5. Once set it stays that way.
*/
function mdsiHeight2Click (height)
{
var cbx = $byId('checkboxHeight2');
var label = $byId('controlHeight2');
if (typeof height != 'undefined')
mdsi_HistoryHeight2 = height;
else
if (mdsi_HistoryHeight2 == 1)
mdsi_HistoryHeight2 = 2;
else
mdsi_HistoryHeight2 = 1;
cbx.checked = true;
label.innerHTML = 'x' + mdsi_HistoryHeight2 + ' ';
var x2 = mdsi_HistoryHeight2 * 100;
mdsiSetHistoryHeight(x2);
mdsiGraphDynamic();
if (mdsi_DiskDisplay) mdsiGraphDisk();
if (mdsi_PerProcessPid) mdsiGraphPerProcess();
acmeAdjustSize();
}
///////////////////////////////////////////////////////////////////////////////
/*
The collection/display checkbox has been clicked from 5->15 or 15->5.
The number of seconds to store the data is bumped in the 5->15 transition but
not reset with the 15->5. Once set it stays that way.
*/
function mdsiMinutesClick (mins)
{
var cbx = $byId('checkboxMinutes');
var label = $byId('controlMinutes');
if (typeof mins != 'undefined')
mdsi_HistoryMinutes = mins;
else
if (mdsi_HistoryMinutes == 5)
mdsi_HistoryMinutes = 15;
else
mdsi_HistoryMinutes = 5;
cbx.checked = true;
label.innerHTML = '' + mdsi_HistoryMinutes + ' Minutes';
if (mdsi_HistoryMinutes == 5)
mdsiSetHistoryWidth(mdsi_HistWidth5);
else
mdsiSetHistoryWidth(mdsi_HistWidth15);
mdsiGraphDynamic();
if (mdsi_DiskDisplay) mdsiGraphDisk();
if (mdsi_PerProcessPid) mdsiGraphPerProcess();
acmeAdjustSize();
}
///////////////////////////////////////////////////////////////////////////////
/*
Tips checkbox has been clicked.
*/
function mdsiAlertsClick (state)
{
var cbx = $byId('checkboxAlerts');
if (state == null) state = false;
if (typeof state == 'undefined') state = !mdsi_AlertsDisplay;
mdsi_AlertsDisplay = cbx.checked = state;
}
///////////////////////////////////////////////////////////////////////////////
/*
Disk checkbox has been clicked.
*/
function mdsiDiskClick (state)
{
if (!mdsi_StaticData || !mdsi_StaticData.diskCount)
{
$byId('checkboxDiskDelta').disabled = false;
$byId('checkboxDiskQlen').disabled = false;
return;
}
if (typeof state == 'undefined') state = !mdsi_DiskDisplay;
mdsi_DiskDisplay = state;
$byId('checkboxDisk').checked = state;
$byId('checkboxDiskQlen').disabled = !state;
$byId('checkboxDiskDelta').disabled = !state;
$byId('perDiskBar').style.display = state ? 'block' : 'none';
$byId('perDiskHist').style.display = state ? 'block' : 'none';
if (!state) mdsi_DiskData = null;
if ($WebSocket)
acmeIpcSend(mdsiTheseData());
else
{
mdsiGraphDisk();
mdsiDiskQlenClick(mdsi_DiskQlenDisplay);
mdsiDiskDeltaClick(mdsi_DiskDeltaDisplay);
}
acmeAdjustSize();
}
///////////////////////////////////////////////////////////////////////////////
/*
Disk queue length checkbox has been clicked.
*/
function mdsiDiskQlenClick (state)
{
if (!mdsi_StaticData || !mdsi_StaticData.diskCount) return;
if (typeof state == 'undefined') state = !mdsi_DiskQlenDisplay;
mdsi_DiskQlenDisplay = state;
var cnt = mdsi_StaticData.diskCount;
for (var idx = 0; idx < cnt; idx++)
{
if (mdsi_DiskQlenDisplay)
$byId('perDiskHistQlen'+idx).style.display = 'inline-block';
else
$byId('perDiskHistQlen'+idx).style.display = 'none';
}
mdsiGraphDisk();
acmeAdjustSize();
$byId('checkboxDiskQlen').checked = state;
}
///////////////////////////////////////////////////////////////////////////////
/*
Disk space delta checkbox has been clicked.
*/
function mdsiDiskDeltaClick (state)
{
if (!mdsi_StaticData || !mdsi_StaticData.diskCount) return;
if (typeof state == 'undefined') state = !mdsi_DiskDeltaDisplay;
mdsi_DiskDeltaDisplay = state;
var cnt = mdsi_StaticData.diskCount;
for (var idx = 0; idx < cnt; idx++)
{
if (mdsi_DiskDeltaDisplay)
$byId('perDiskHistDelta'+idx).style.display = 'inline-block';
else
$byId('perDiskHistDelta'+idx).style.display = 'none';
}
mdsiGraphDisk();
acmeAdjustSize();
$byId('checkboxDiskDelta').checked = state;
}
///////////////////////////////////////////////////////////////////////////////
/*
(CPU) Modes checkbox has been clicked.
*/
function mdsiModesClick (state)
{
var cbx = $byId('checkboxModes');
var htab1 = $byId('cpuHist');
var htab2 = $byId('cpuModesHist');
var htab3 = $byId('cpuModesData');
if (typeof state == 'undefined') state = !mdsi_ModesDisplay;
mdsi_ModesDisplay = cbx.checked = state;
htab1.style.display = state ? 'none': 'inline-block';
htab2.style.display = state ? 'inline-block' : 'none';
htab3.style.display = state ? 'block' : 'none';
acmeAdjustSize();
}
///////////////////////////////////////////////////////////////////////////////
/*
Process checkbox has been clicked.
*/
function mdsiProcessClick (state)
{
var cbx = $byId('checkboxProcess');
var div = $byId('processDiv');
if (typeof state == 'undefined') state = !mdsi_ProcessDisplay;
if (state)
{
mdsi_ProcessDisplay = true;
cbx.checked = true;
div.style.display = 'block';
}
else
{
mdsi_ProcessDisplay = false;
mdsi_TopProcessData = mdsi_PerProcessData = null;
mdsiTopPidClick();
mdsiDisplayTopProcess(true);
mdsi_PerHistoryDisplay = true;
mdsiPerHistoryClick(false);
cbx.checked = false;
div.style.display = 'none';
}
if ($WebSocket)
acmeIpcSend(mdsiTheseData());
else
mdsiDisplayTopProcess(false);
acmeAdjustSize();
}
///////////////////////////////////////////////////////////////////////////////
/*
Cluster checkbox has been clicked.
*/
function mdsiClusterClick (state)
{
var cbx = $byId('checkboxCluster');
var bar = $byId('clusterBar');
var hist = $byId('clusterHistory');
if (typeof state == 'undefined') state = !mdsi_ClusterDisplay;
if (state)
{
mdsi_ClusterDisplay = true;
cbx.checked = true;
bar.style.display = hist.style.display = 'block';
}
else
{
mdsi_ClusterDisplay = false;
cbx.checked = false;
bar.style.display = hist.style.display = 'none';
}
if ($WebSocket) acmeIpcSend(mdsiTheseData());
mdsiDisplaySummary();
acmeAdjustSize();
}
///////////////////////////////////////////////////////////////////////////////
/*
Generate a parameter string of current interests. This parameter string is
used to convey interests to the executable via WebSocket IPC and as query
string parameters in the case of XHR requests.
*/
function mdsiTheseData ()
{
var these = '';
if ($WebSocket)
{
if (mdsi_ClusterDisplay) these += 'cluster=1';
if (mdsi_DiskDisplay)
{
// once disk is enabled don't disable it again
if (these.length) these += '&';
these += 'disk=1';
}
if (these.length) these += '&';
if (mdsi_OpcomDisplay)
{
these += 'opcom=1';
if (mdsi_OpcomAudit)
these += '&audit=1';
else
these += '&audit=0';
}
else
these += 'opcom=0&audit=0';
if (these.length) these += '&';
if (mdsi_ProcessDisplay)
these += 'process=1';
else
these += 'process=0';
}
if (these.length) these += '&';
these += 'pid=' + mdsi_PerProcessPid + '';
return(these);
}
///////////////////////////////////////////////////////////////////////////////