diff options
author | Tobi Oetiker <tobi@oetiker.ch> | 2008-06-02 22:03:33 +0200 |
---|---|---|
committer | Tobi Oetiker <tobi@oetiker.ch> | 2008-06-02 22:03:33 +0200 |
commit | 8793d83042d5cf388a30ee5f8637fa6554334aa6 (patch) | |
tree | ca1d1a68cd3513f1eab9fa9a14559f687d233aae /qooxdoo/source/class | |
parent | 6b239270a134ef8f26d59a7ab9b35eeeeceb9c47 (diff) | |
download | smokeping-8793d83042d5cf388a30ee5f8637fa6554334aa6.tar.gz smokeping-8793d83042d5cf388a30ee5f8637fa6554334aa6.tar.xz |
initial support for mrt integration
Diffstat (limited to 'qooxdoo/source/class')
-rw-r--r-- | qooxdoo/source/class/Mtr/Application.js | 89 | ||||
-rw-r--r-- | qooxdoo/source/class/Mtr/Server.js | 74 | ||||
-rw-r--r-- | qooxdoo/source/class/Mtr/ui/ActionButton.js | 160 | ||||
-rw-r--r-- | qooxdoo/source/class/Mtr/ui/Cellrenderer.js | 46 | ||||
-rw-r--r-- | qooxdoo/source/class/Mtr/ui/TraceTable.js | 215 |
5 files changed, 584 insertions, 0 deletions
diff --git a/qooxdoo/source/class/Mtr/Application.js b/qooxdoo/source/class/Mtr/Application.js new file mode 100644 index 0000000..7d28f59 --- /dev/null +++ b/qooxdoo/source/class/Mtr/Application.js @@ -0,0 +1,89 @@ +/* ************************************************************************ + +#module(Mtr) +#resource(Mtr.image:image) +#embed(Mtr.image/*) + +************************************************************************ */ + +qx.Class.define('Mtr.Application', +{ + extend: qx.application.Gui, + + members: + { + main: function() + { + var self=this; + this.base(arguments); + + qx.io.Alias.getInstance().add( + 'MT', qx.core.Setting.get('Mtr.resourceUri') + ); + + // if we run with a file:// url make sure + // the app finds the Mtr service (Mtr.cgi) + + Mtr.Server.getInstance().setLocalUrl( + 'http://johan.oetiker.ch/~oetiker/mtr/' + ); + + var base_layout = new qx.ui.layout.VerticalBoxLayout(); + with(base_layout){ + setPadding(8); + setLocation(0,0); + setWidth('100%'); + setHeight('100%'); + setSpacing(10); + setBackgroundColor('white'); + }; + base_layout.addToDocument(); + var top = new qx.ui.layout.HorizontalBoxLayout(); + top.set({ + height: 'auto' + }); + var title = new qx.ui.basic.Atom(this.tr("MTR AJAX Frontend")); + with(title){ + setTextColor('#b0b0b0'); + setFont(qx.ui.core.Font.fromString('20px bold sans-serif')); + } + top.add(title); + top.add(new qx.ui.basic.HorizontalSpacer()); + top.add(new Mtr.ui.ActionButton()); + base_layout.add(top); + var trace = new Mtr.ui.TraceTable(); + base_layout.add(trace); + }, + + close : function(e) + { + this.base(arguments); + // return "Mtr Web UI: " + // + "Do you really want to close the application?"; + }, + + + terminate : function(e) { + this.base(arguments); + } + + /******************************************************************** + * Functional Block Methods + ********************************************************************/ + + }, + + + + + /* + ***************************************************************************** + SETTINGS + ***************************************************************************** + */ + + settings : { + 'Mtr.resourceUri' : './resource' + } +}); + diff --git a/qooxdoo/source/class/Mtr/Server.js b/qooxdoo/source/class/Mtr/Server.js new file mode 100644 index 0000000..3e77047 --- /dev/null +++ b/qooxdoo/source/class/Mtr/Server.js @@ -0,0 +1,74 @@ +/* ************************************************************************ +#module(Mtr) +************************************************************************ */ + +/** + * A Mtr specific rpc call which works + */ + +qx.Class.define('Mtr.Server', { + extend: qx.io.remote.Rpc, + type: "singleton", + + /* + ***************************************************************************** + CONSTRUCTOR + ***************************************************************************** + */ + + /** + * @param local_url {String} When running the application in file:// mode. + * where will we find our RPC server. + */ + construct: function (local_url) { + + with(this){ + base(arguments); + setTimeout(7000000); + setUrl('mtr.cgi'); + setServiceName('Mtr'); + setCrossDomain(true); + } + + return this; + }, + + /* + ***************************************************************************** + MEMBERS + ***************************************************************************** + */ + + members : + { + + /* + --------------------------------------------------------------------------- + CORE METHODS + --------------------------------------------------------------------------- + */ + + /** + * Tell about the BaseUrl we found. + * + * @type member + * + * @param {void} + * + * @return BaseUrl {Strings} + */ + + getBaseUrl: function(){ + return this.__base_url; + }, + + setLocalUrl: function(local_url){ + if ( document.location.host === '' ) { + with(this){ + setUrl(local_url+'mtr.cgi'); + } + } + } + + } +}); diff --git a/qooxdoo/source/class/Mtr/ui/ActionButton.js b/qooxdoo/source/class/Mtr/ui/ActionButton.js new file mode 100644 index 0000000..0c02598 --- /dev/null +++ b/qooxdoo/source/class/Mtr/ui/ActionButton.js @@ -0,0 +1,160 @@ +/* ************************************************************************ +#module(Mtr) +************************************************************************ */ + +/** + * a widget showing the Mtr graph overview + */ + +qx.Class.define('Mtr.ui.ActionButton', +{ + extend: qx.ui.layout.HorizontalBoxLayout, + + /* + ***************************************************************************** + CONSTRUCTOR + ***************************************************************************** + */ + + construct: function () { + this.base(arguments); + + this.set({ + height: 'auto', + width: 'auto', + verticalChildrenAlign: 'middle' + }); + var lab1 = new qx.ui.basic.Label(this.tr("Host")); + lab1.set({ + paddingRight: 6 + }); + this.add(lab1); + var host = new qx.ui.form.TextField(); + host.set({ + width: 200, + height: 'auto', + border: 'dark-shadow', + padding: 1 + }); + this.add(host); + this.__host = host; + + var lab2 = new qx.ui.basic.Label(this.tr("Delay")); + lab2.set({ + paddingRight: 6, + paddingLeft: 12 + }); + this.add(lab2); + var delay = new qx.ui.form.Spinner(1,5,60); + delay.set({ + border: 'dark-shadow' + }); + this.add(delay); + this.__delay = delay; + + var lab3 = new qx.ui.basic.Label(this.tr("Rounds")); + lab3.set({ + paddingRight: 6, + paddingLeft: 12 + }); + this.add(lab3); + var rounds = new qx.ui.form.Spinner(1,20,200); + rounds.set({ + border: 'dark-shadow' + }); + this.add(rounds); + this.__rounds = rounds; + + var button = new qx.ui.form.Button(''); + this.__button = button; + button.set({ + marginLeft: 10, + width: 50, + height: 'auto', + border: 'dark-shadow', + padding: 2 + }); + this.add(button); + + qx.event.message.Bus.subscribe('mtr.status',this.__set_status,this); + qx.event.message.Bus.dispatch('mtr.status','stopped'); + + var start_trace = function(event) { + qx.event.message.Bus.dispatch('mtr.cmd',{ + action: button.getUserData('action'), + host: host.getValue(), + delay: delay.getValue(), + rounds: rounds.getValue() + }); + }; + + button.addEventListener('execute', start_trace ); + + var history_action = function(event){ + host.setValue(event.getData()); + start_trace(); + } + qx.client.History.getInstance().addEventListener('request', history_action); + + // if we got called with a host on the commandline + var initial_host = qx.client.History.getInstance().getState(); + if (initial_host){ + host.setValue(initial_host); + // dispatch this task once all the initializations are done + qx.client.Timer.once(start_trace,this,0); + } + }, + + members: { + __set_status: function(m){ + var host = this.__host; + var rounds = this.__rounds; + var delay = this.__delay; + with(this.__button){ + // this.debug(m.getData()); + switch(m.getData()){ + case 'starting': + if (getUserData('action') == 'go') { + setLabel(this.tr("Starting")); + setEnabled(false); + host.setEnabled(false); + rounds.setEnabled(false); + delay.setEnabled(false); + } + break; + case 'stopping': + if (getUserData('action') == 'stop') { + setLabel(this.tr("Stopping")); + setEnabled(false); + host.setEnabled(false); + rounds.setEnabled(false); + delay.setEnabled(false); + } + break; + case 'stopped': + setUserData('action','go'); + setLabel(this.tr("Go")); + setEnabled(true); + host.setEnabled(true); + rounds.setEnabled(true); + delay.setEnabled(true); + break; + case 'started': + setUserData('action','stop'); + setLabel(this.tr("Stop")); + setEnabled(true); + host.setEnabled(false); + rounds.setEnabled(false); + delay.setEnabled(false); + break; + default: + alert('Unknown Status Message: '+m.getData()); + } + } + } + } + + +}); + + diff --git a/qooxdoo/source/class/Mtr/ui/Cellrenderer.js b/qooxdoo/source/class/Mtr/ui/Cellrenderer.js new file mode 100644 index 0000000..2b2e45e --- /dev/null +++ b/qooxdoo/source/class/Mtr/ui/Cellrenderer.js @@ -0,0 +1,46 @@ +/* ************************************************************************ + + Mtr Frontend + + Author: + * Tobias Oetiker + +************************************************************************ */ +/* ************************************************************************ +#module(Mtr) +************************************************************************ */ + +/** + * A configurable cell renderre + */ + +qx.Class.define('Mtr.ui.Cellrenderer', +{ + extend: qx.ui.table.cellrenderer.Number, + /** + * Format a number with a configurable number of fraction digits + * and add optional pre and postfix. + * @param digits {Integer} how many digits should there be. Default is 0. + * @param prefix {String} optional prefix. + * @param postfix {String} optional postfix. + */ + + construct: function (digits,postfix,prefix) { + if (digits == undefined){ + digits = 0; + } + this.base(arguments) + var format = new qx.util.format.NumberFormat(); + format.set({ + maximumFractionDigits: digits, + minimumFractionDigits: digits + }); + if (postfix != undefined){ + format.setPostfix(postfix); + } + if (prefix != undefined){ + format.setPrefix(prefix); + } + this.setNumberFormat(format); + } +}); diff --git a/qooxdoo/source/class/Mtr/ui/TraceTable.js b/qooxdoo/source/class/Mtr/ui/TraceTable.js new file mode 100644 index 0000000..1097f22 --- /dev/null +++ b/qooxdoo/source/class/Mtr/ui/TraceTable.js @@ -0,0 +1,215 @@ +/* ************************************************************************ +#module(Mtr) +************************************************************************ */ + +/** + * a widget showing the Mtr target tree + */ + +qx.Class.define('Mtr.ui.TraceTable', +{ + extend: qx.ui.table.Table, + + /* + ***************************************************************************** + CONSTRUCTOR + ***************************************************************************** + */ + + + construct: function () { + + var tableModel = new qx.ui.table.model.Simple(); + this.__tableModel = tableModel; + tableModel.setColumns([ this.tr("Hop"), this.tr("Host"),this.tr("Ip"), + this.tr("Loss [%]"), this.tr("Sent [ms]"), this.tr("Last [ms]"), //"; help syntax highliter + this.tr("Avg [ms]"), this.tr("Best [ms]"), this.tr("Worst [ms]"), this.tr("StDev [ms]") ]); + var custom = { + tableColumnModel: function(obj) { + return new qx.ui.table.columnmodel.Resize(obj); + } + }; + with(this){ + base(arguments,tableModel,custom); + set({ + width: '100%', + height: '1*', + border: 'dark-shadow', + showCellFocusIndicator: false, + statusBarVisible: false + }); + }; + var tcm = this.getTableColumnModel(); + + tcm.setDataCellRenderer(3, new Mtr.ui.Cellrenderer(0,' %')); + tcm.setDataCellRenderer(4, new Mtr.ui.Cellrenderer(0)); + + var render_ms = new Mtr.ui.Cellrenderer(1); + + for (var i=5;i<10;i++){ + tcm.setDataCellRenderer(i, render_ms); + } + + + // Obtain the behavior object to manipulate + var resizeBehavior = tcm.getBehavior(); + // This uses the set() method to set all attriutes at once; uses flex + resizeBehavior.set(0, { width:"1*", minWidth:20, maxWidth:30 }); + resizeBehavior.set(1, { width:"10*", minWidth:80, maxWidth:300 }); + resizeBehavior.set(2, { width:"6*", minWidth:60, maxWidth:200 }); + + for (var i=3;i<10;i++){ + resizeBehavior.set(i, { width:"2*", minWidth:40, maxWidth:100 }); + } + qx.event.message.Bus.subscribe('mtr.cmd',this.__handle_mtr,this); + }, + + /* + ***************************************************************************** + Statics + ***************************************************************************** + */ + members: { + __make_empty_row: function (){ + return ([undefined,'waiting for name','waiting for ip',0,0,undefined,undefined,undefined,undefined,undefined,0,0,0]); + }, + __handle_mtr: function(m){ + var self = this; + var f_hop = 0,f_host=1,f_ip=2,f_loss=3,f_snt=4,f_last=5,f_avg=6,f_best=7,f_worst=8,f_stdev=9,f_cnt=10,f_sum=11,f_sqsum=12; + var fill_table; + fill_table = function(retval,exc,id){ + if (exc == null){ + if ( self.__handle == undefined ) { + qx.event.message.Bus.dispatch('mtr.status','started'); + } + self.__handle = retval['handle']; + var tableModel = self.__tableModel; + var rowcount = tableModel.getRowCount(); + var lines = retval['output'].length; + var data = self.__data; + for(var i=0;i<lines;i++){ + var cmd = retval['output'][i][0]; + var row = retval['output'][i][1]; + var value = retval['output'][i][2]; + if (rowcount <= row){ + for (var ii=rowcount;rowcount <= row;rowcount++){ + data.push(self.__make_empty_row()); + }; + }; + var drow = data[row]; + drow[f_hop] = row+1; + switch(cmd){ + case 'h': + drow[f_ip] = value; + break; + case 'd': + drow[f_host] = value; + break; + case 'p': + var snt = data[0][f_snt]; + if (row == 0) { + snt++; + for (ii=0;ii<rowcount;ii++){ + if (retval['again'] && snt > data[ii][f_cnt]){ + data[ii][f_snt] = snt-1; + } else { + data[ii][f_snt] = snt; + } + data[ii][f_loss]=(1-data[ii][f_cnt]/data[ii][f_snt])*100; + } + } + value = value/1000.0; + drow[f_last] = value; + + var best = drow[f_best]; + if (best == undefined || best > value){ + drow[f_best] = value; + } + + var worst = drow[f_worst]; + if (worst == undefined || worst < value){ + drow[f_worst] = value; + } + + var cnt = drow[f_cnt]+1; + + if (cnt > drow[f_snt]){ + drow[f_snt] = cnt; + } + + drow[f_cnt] = cnt; + + drow[f_loss] = (1-cnt/drow[f_snt])*100; + + var sum = drow[f_sum]+value; + drow[f_sum] = sum; + var sqsum = drow[f_sqsum]+value*value; + drow[f_sqsum] = sqsum; + + drow[f_avg] = sum/cnt; + drow[f_stdev] = Math.sqrt((cnt*sqsum-sum*sum)/(cnt*(cnt-1))) + break; + + default: + self.debug(row); + break; + } + } + + tableModel.setData(data); + if (retval['again']){ + var next_round = function (){Mtr.Server.getInstance().callAsync( + fill_table,'run_mtr',{ handle: retval['handle'], + point: retval['point']})}; + qx.client.Timer.once(next_round,self,0); + } else + { + for (var i=0;i<10;i++){ + tableModel.setColumnSortable(i,true); + } + qx.event.message.Bus.dispatch('mtr.status','stopped'); + self.__handle = undefined; + } + } + else { + alert(exc); + if (self.__handle){ + self.__handle = undefined; + } + for (var i=0;i<10;i++){ + self.__tableModel.setColumnSortable(i,true); + } + qx.event.message.Bus.dispatch('mtr.status','stopped'); + } + }; + + var handle_returns = function (data,exc,id){ + if (exc != null){ + alert(exc); + } + }; + + var cmd = m.getData(); + switch(cmd['action']){ + case 'stop': + qx.event.message.Bus.dispatch('mtr.status','stopping'); + Mtr.Server.getInstance().callAsync(handle_returns,'stop_mtr',this.__handle); + break; + case 'go': + this.__data = [this.__make_empty_row()]; + this.__tableModel.setData(this.__data); + this.__delay = cmd['delay']; + for (var i=0;i<10;i++){ + this.__tableModel.setColumnSortable(i,false); + } + qx.event.message.Bus.dispatch('mtr.status','starting'); + Mtr.Server.getInstance().callAsync(fill_table,'run_mtr',{host: cmd['host'], rounds: cmd['rounds'], delay: cmd['delay']}); + break; + default: + alert('Unknown Command '+cmd['action']); + } + } + } +}); + + |