<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
<script src="smoothie.js"></script>
<style type="text/css">
body { width:100%; height:100%; margin:0; padding:0; overflow: scroll; }
svg, div, canvas { margin:0; padding:0; }
table, td { border: 1px solid black; text-align: center; }
.clientTable
{
display: table;
width:auto;
background-color:#eee;
border:1px solid #666666;
border-spacing:5px;
}
.speed
{
align-content: right;/*fix for buggy browsers*/
width:240px;
background-color:#E0E0E0;
background: linear-gradient(90deg, #E0E0E0 100%, #9DA7AE 0%);
}
.noBorder
{
text-align: left;
border: none;
}
.serverTd
{
border:none;
font-weight: bold;
}
.serverLTd
{
border:none;
font-weight: bold;
text-align: left;
}
</style>
</head>
<body>
<div id="bigDiv">
<!-- <div style="float:left" >
<table class="clientTable" id="Table">
<tbody>
<tr class="firstRow">
<td>Client Ip</td><td class='speed'>Download Speed from </td>
</tr>
</tbody>
</table> -->
</div>
<!--
<div style="float:left">
<table class="clientTable" id="otherTable">
<tbody>
<tr class="firstRow">
<td>Client Ip</td><td class='speed'>Client Speed</td>
</tr>
</tbody>
</table>
</div> -->
<div id="statistics"><div id="debug"></div></div>
<div> <canvas id="traffic" width="100%" height="150"></canvas></div>
</body>
<script type="text/javascript">
var lock = false;
var lastTime = 0;
var posibleNrOfRows = 23;
var newAndOld = { 'new':{}, 'old':{} };
var servClSpeeds = {'fresh':0};
var sortedClSpeeds = {'fresh':0, 'nrOfServers':0};
var serverStats = {};
var serverNewAndOld = { 'new':{}, 'old':{} };
// Get new data
setInterval( function() {
$.get('/data2.json', function(data) {
if (data.timestamp < lastTime) lastTime = data.timestamp;
if(data.timestamp === lastTime) return;
var servers = data.servers;
// take what we need; give nothing back
var parsedServers = parseServers( servers );
var parsedServersForStats = parseServersForStats( servers );
newAndOld['new'] = parsedServers;
serverNewAndOld['new'] = parsedServersForStats;
update_servClSpeeds( newAndOld );
update_serverStats( serverNewAndOld );
if ( servClSpeeds.fresh !== 0 ) { update_sortedClSpeeds(servClSpeeds); }
if ( sortedClSpeeds.fresh !== 0 ) {
// TODO:
// do stuff with the sorted stuff and stuff and stuff
dostuff( sortedClSpeeds, serverStats );
}
servClSpeeds['fresh'] = 1;
lastTime = data.timestamp;
newAndOld['old'] = parsedServers;
serverNewAndOld['old'] = parsedServersForStats;
}, 'json').always(function() {
});
}, 2000);
// changes the colors of the tds holding the download speed
// color code and details follow bellow
function makeItPretty( clArray ) {
for ( var key in clArray ) {
for ( var client in clArray[key]) {
var wrappedIp = ipWrapper( client );
var Bps = clArray[key][client];
var td = $( "." + wrappedIp + " > " + ".speed");
td.css("background", changeBackground1( Bps ) );
}
}
}
function changeBackground1 ( speed ) {
var result = "";
switch ( true ) {
case speed < 1024:
var proc = ( ( speed * 10 ) / 1024 );
var proc2 = Math.round( proc );
result = " linear-gradient(-90deg, #E0E0E0 "+(100-proc2)+"%, #8adb8b "+proc2+"%)";
break;
case ( speed >= 1024 && speed < 10240 ):
var proc = ( ( speed * 10 ) / 10240 );
var proc2 = Math.round( proc );
result = " linear-gradient(-90deg, #E0E0E0 "+(100-proc2-10)+"%, #8adb8b "+(proc2+10)+"%)";
break;
case ( speed >= 10240 && speed < 102400 ):
var proc = ((speed * 10) / 102400 );
var proc2 = Math.round( proc );
result = " linear-gradient(-90deg, #E0E0E0 "+(100-proc2-20)+"%, #8adb8b "+(proc2+20)+"%)";
break;
case ( speed >= 102400 && speed < 1048576 ):
var proc = ((speed * 10) / 1048576 );
var proc2 = Math.round( proc );
result = " linear-gradient(-90deg, #E0E0E0 "+(100-proc2-30)+"%, #5cdb55 "+(proc2+30)+"%)";
break;
case ( speed >= 1048576 && speed < 10485760 ):
var proc = ((speed * 10) / 10485760 );
var proc2 = Math.round( proc );
result = " linear-gradient(-90deg, #E0E0E0 "+(100-proc2-40)+"%, #5cdb55 "+(proc2+40)+"%)";
break;
case ( speed >= 10485760 && speed < 104857600 ):
var proc = ( ( speed * 10 ) / 104857600 );
var proc2 = Math.round( proc );
result = " linear-gradient(90deg, #5cdb55 "+(proc2+50)+"%, #E0E0E0 "+(50-proc2)+"%)";
break;
case ( speed >= 104857600 && speed < 1073741824 ):
var proc = ( ( speed * 10 ) / 1073741824 );
var proc2 = Math.round( proc );
result = " linear-gradient(90deg, #26a81f "+(proc2+60)+"%, #E0E0E0 "+(40-proc2)+"%)";
break;
case ( speed >= 1073741824 && speed <= 10737418240 ):
var proc = ( ( speed * 10 ) / 10737418240 );
var proc2 = Math.round( proc );
result = " linear-gradient(90deg, #26a81f "+(proc2+70)+"%, #E0E0E0 "+(30-proc2)+"%)";
break;
case ( speed >= 10737418240 && speed <= 107374182400 ):
var proc = ( ( speed * 10 ) / 107374182400 );
var proc2 = Math.round( proc );
result = " linear-gradient(90deg, #26a81f "+(proc2+80)+"%, #E0E0E0 "+(20-proc2)+"%)";
break;
case ( speed >= 107374182400 && speed < 1099511627776 ):
var proc = ( ( speed * 10 ) / 1099511627776 );
var proc2 = Math.round( proc );
result = " linear-gradient(90deg, #056d00 "+(proc2+90)+"%, #E0E0E0 "+(10-proc2)+"%)";
break;
case ( speed > 10995116277760 ):
var proc = ( ( speed * 10 ) / 10995116277760 );
var proc2 = proc < 10 ? Math.round( proc ) : 10;
result = " linear-gradient(90deg, #056d00 "+(proc2+90)+"%, #E0E0E0 "+(10-proc2)+"%)";
break;
}
return result;
}
function changeBackground2 ( speed ) {
var result = "";
switch ( true ) {
case speed < 524288:
var proc = ( ( speed * 25 ) / 524288 );
var proc2 = Math.round( proc );
result = " linear-gradient(-90deg, #E0E0E0 "+(100-proc2)+"%, #5fce33 "+proc2+"%)";
break;
case ( speed >= 524288 && speed < 1048576 ):
var proc = ( ( speed * 25 ) / 1048576 );
var proc2 = Math.round( proc );
result = " linear-gradient(-90deg, #5fce33 "+(100-proc2-25)+"%, #1f6b01 "+(proc2+25)+"%)";
break;
case ( speed >= 1048576 && speed < 536870912 ):
var proc = ( ( speed * 25 ) / 536870912 );
var proc2 = Math.round( proc );
result = " linear-gradient(90deg, #ef396d "+(proc2+50)+"%, #1f6b01 "+(50-proc2)+"%)";
break;
case ( speed >= 536870912 && speed < 1073741824 ):
var proc = ( ( speed * 25 ) / 1073741824 );
var proc2 = Math.round( proc );
result = " linear-gradient(90deg, #870014 "+(proc2+75)+"%, #ef396d "+(25-proc2)+"%)";
break;
case ( speed > 1073741824 ):
result = " linear-gradient(90deg, #0285ea 100%, #ad001a 0%)";
break;
}
return result;
}
// create as many divs as servers...append them to the bigDiv...if a small div already exists...move to
// the next one
function createTheDivz ( servArray ) {
lock = true;
for( i = 0; i < servArray.length; i++ ) {
var wrappedIp = ipWrapper( servArray[i] );
if ( $( "#div-" + wrappedIp ).length > 0 ) {
$( "#div-" + wrappedIp ).remove();
}
var servDiv = $( '<div></div>' );
servDiv.attr( 'id', "div-" + wrappedIp );
servDiv.attr( 'style', "float:left" );
$( "#bigDiv" ).append( servDiv );
}
}
// simple function creates a table from a given server ip, its clients and a number of rows
function buildTable ( servIp, clArray , nrOfRows, statsObj ) {
// test to see if the number of rows to be shown exceeds the number of existing clients
// if yes replace number of shown rows with the length of clients array(represents the nr of clients)
var localRows = nrOfRows;
if ( nrOfRows > clArray.length ) { localRows = clArray.length; }
// if table object already exists delete it
var wrappedIp = ipWrapper( servIp );
if ( $( "#tbl-" + wrappedIp ).length > 0 ) {
$( "#tbl-" + wrappedIp ).remove();
}
var servTable = $( "<table></table>" ).addClass( "clientTable" );
servTable.attr( "id", "tbl-" + wrappedIp );
var row1 = $( "<tr></tr>" ).addClass( 'row1' );
var lCol1 = $( "<td></td>" ).addClass("serverLTd").text( "Server Ip: " );
var rCol1 = $( "<td></td>" ).addClass("serverTd").text( servIp );
row1.append( lCol1 );
row1.append( rCol1 );
servTable.append( row1 );
for ( var key in statsObj[servIp] ) {
if ( key === "address" || key === "timestamp") { continue; }
var server = statsObj[servIp];
var row = $( "<tr></tr>" );
var lCol = $( "<td></td>" ).addClass("noBorder").text( key +": " );
var value = server[key];
var rCol = $( "<td></td>" ).addClass("noBorder").text( value );
row.append( lCol );
row.append( rCol );
servTable.append( row );
}
for( var key in clArray ) {
for( var client in clArray[key] ) {
var row = $( "<tr></tr>" ).addClass( ipWrapper( client ) );
var lCol = $( "<td></td>" ).text( client );
var rCol = $( "<td></td>" ).addClass( 'speed' ).text( bytesToString( clArray[key][client] ) );
}
row.append( lCol );
row.append( rCol );
servTable.append( row );
}
$( "#div-" + wrappedIp ).append( servTable );
}
// do stuff stuff stuff stuffy stuff
function dostuff( obj, statsObj ) {
// the servers in an array sorted after the number of clients...index 0 the server with the most
// clients...will also receive the leftmost table
var leServers = sortServers( obj );
if (lock == false ) { createTheDivz( leServers ) };
for( i = 0; i < leServers.length; i++ ) {
var wrappedIp = ipWrapper(leServers[i]);
if(! $( "#div-" + wrappedIp ).length > 0 ) { continue; }
var serverIp = leServers[i];
var clientsArray = obj[serverIp];
buildTable( serverIp, clientsArray, posibleNrOfRows, statsObj );
makeItPretty( clientsArray );
// -- TODO figure a way to play with the colours again...consider using the whole object or just each array
// try both...
}
}
// little helper function to wrap the Ip and replace all the . with - and add a c at the start of the ip
// needed for the html table because the rows cannot have an id with . in it
function ipWrapper( givenIp ) {
var localIp = givenIp.replace(/\./g, "-");
return "c"+localIp;
}
// function that give us the servers ip which has the most clients
function sortServers( obj ) {
var keys = [];
for(var key in obj) {
if( key == 'fresh' || key == "nrOfServers" ) { continue; }
keys.push( key );
}
var sortedKeys = keys.sort( function( a, b ) { return obj[b].length - obj[a].length; } );
return sortedKeys;
}
function update_serverStats ( obj ) {
for( var key in obj['new'] ) {
var localObject = {};
if( key in obj['old'] ) {
var newObject = obj['new'][key];
var oldObject = obj['old'][key];
var stime = ( newObject.timestamp <= oldObject.timestamp ) ?
2 :
( newObject.timestamp - oldObject.timestamp ) / 1000;
localObject['address'] = newObject.address;
localObject['timestamp'] = newObject.timestamp < oldObject.timestamp ?
newObject.timestamp :
newObject.timestamp - oldObject.timestamp;
localObject['uptime'] = Math.floor(newObject.uptime / ( 3600 * 24 ) ) + "d " +
Math.floor(newObject.uptime / 3600 ) % 24 + "h " +
Math.floor(newObject.uptime / 60 ) % 60 + "min";
var uploadSpeed = newObject.bytesSent < oldObject.bytesSent ?
0 :
Math.round(
(newObject.bytesSent - oldObject.bytesSent)
/ stime);
localObject['uploadSpeed'] = bytesToString(uploadSpeed);
var downloadSpeed = newObject.bytesReceived < oldObject.bytesReceived ?
0 :
Math.round(
(newObject.bytesReceived - oldObject.bytesReceived)
/ stime);
localObject['downloadSpeed'] = bytesToString(downloadSpeed);
var localBytesSent = (newObject.bytesSent < oldObject.bytesSent) ?
oldObject.bytesSent : newObject.bytesSent;
localObject['Total sent'] = bytesToString( localBytesSent );
var localBytesReceived = (newObject.bytesReceived < oldObject.bytesReceived) ?
oldObject.bytesReceived : newObject.bytesReceived;
localObject['Total received'] = bytesToString( localBytesReceived );
serverStats[localObject.address] = localObject;
}
}
}
// update function for the servClSpeeds object
function update_servClSpeeds ( obj ) {
for( var key in obj['new'] ) {
if( key in obj['old'] ) {
var newObject = obj['new'][key];
var oldObject = obj['old'][key];
var resultObject = speedCalc( newObject, oldObject );
servClSpeeds[key] = resultObject;
}
}
}
// update function for the sortedClSpeeds
function update_sortedClSpeeds ( obj ) {
var nrOfServ = 0;
for ( var key in obj ) {
if ( key === 'fresh' ) { continue; }
var clients = obj[key];
var sortedArray = getSortedKeys( clients );
sortedClSpeeds[key] = sortedArray;
nrOfServ++;
}
sortedClSpeeds['fresh'] = 1;
sortedClSpeeds['nrOfServers'] = nrOfServ;
}
// helper function for the sortIps() function
function getSortedKeys( obj ) {
sortedIps = [];
var keys = [];
for( var key in obj ) keys.push( key );
var sortedKeys = keys.sort( function( a, b ) { return obj[b] - obj[a]; } );
for( var i = 0; i < sortedKeys.length; i++) {
var smallObj = {};
var Ip = sortedKeys[i];
var speed = obj[sortedKeys[i]];
smallObj[Ip] = speed;
sortedIps.push( smallObj );
}
return sortedIps;
}
// function that takes the servers-with-clientspeeds object and returns another object that has
// serverips as keys and as values an array of sorted ips with the leftmost element beeing the ip with the
// greatest speed and the rightmost one, the one with the smallest speed
// each element of the array is a string consisting of ip:socket#speedInBytesPerSecond
function sortIps ( obj ) {
var localObject = {};
for( var servip in obj ) {
var localObject = obj[servip];
var localArray = getSortedKeys( localObject );
localObject[serverip] = localArray;
}
return localObject;
}
// function takes new and old parsedServer object and returns a new object where the traffic of each
// client is now replaced by speed in bytes/s
function speedCalc( newO, oldO ){
var localObject = {};
// time in seconds calculated from the difference of timestamps or default 2
// TODO: ask about same timestamp
var stime = ( newO.timestamp <= oldO.timestamp ) ?
2 :
( newO.timestamp - oldO.timestamp ) / 1000;
for( var ip in newO.clients ) {
if( ip in oldO.clients ) {
var bitesDelta = newO.clients[ip] - oldO.clients[ip];
if( bitesDelta < 0 ) { bitesDelta = newO.clients[ip]; }
// take only the active clients
if( bitesDelta != 0 ) {
var speed = Math.round( bitesDelta / stime );
var newClIp = ip.split( ":" )[0];
if( newClIp in localObject ) {
localObject[newClIp] = localObject[newClIp] + speed;
} else {
localObject[newClIp] = speed;
}
}
}
}
return localObject;
}
function parseServersForStats( servers ) {
var parsedServers = {};
var numberOfClients = 0;
for (var i in servers ) {
numberOfClients += servers[i].clientCount;
newServerObject = {};
var timestamp = servers[i].timestamp;
newServerObject['timestamp'] = timestamp;
var serverIp = servers[i].address;
newServerObject['address'] = serverIp;
newServerObject['uptime'] = servers[i].uptime;
newServerObject['bytesSent'] = servers[i].bytesSent;
newServerObject['bytesReceived'] = servers[i].bytesReceived;
parsedServers[serverIp] = newServerObject;
}
return parsedServers;
}
// takes the whole lot of servers and returnes an object whose keys are the server ip and each ip has
// a timestamp and an adjecent clients object
// clients object is just key:value pairs
function parseServers( servers ) {
var parsedServers = {};
// servers is a array containing server objects
for( var i in servers ) {
// object has .clients argument and .timestamp argument
newServerObject = {};
// save and write timestamp of the server
var timestamp = servers[i].timestamp;
newServerObject['timestamp'] = timestamp;
// iterate over clients array and save ip:bytes pairs in local object
var clientsObject = {};
var clients = servers[i].clients;
for( var ii in clients ) {
var key = clients[ii].address;
var value = clients[ii].bytesSent;
clientsObject[key] = value;
}
newServerObject['clients'] = clientsObject;
var serverIp = servers[i].address;
// object shoul know its own name; in this case its ip
newServerObject['address'] = serverIp;
parsedServers[serverIp] = newServerObject;
}
return parsedServers;
}
function serversForStats( servers ) {
}
// Convert bytes to GiB or TiB and return a string in form "10,23 GiB"
function bytesToString( bytes ) {
var convertedValue;
var unit;
if( bytes >= 1099511627776 ) {
convertedValue = Math.round( ( bytes / 1099511627776) * 100 ) / 100 ;
unit = " TiB";
} else if( bytes >= 1073741824 ) {
convertedValue = Math.round( ( bytes / 1073741824) * 100 ) / 100 ;
unit = " GiB";
} else if( bytes >= 1048576 ) {
convertedValue = Math.round( ( bytes / 1048576) * 100 ) / 100 ;
unit = " MiB";
} else if( bytes >= 1024 ) {
convertedValue = Math.round( ( bytes / 1024) * 100 ) / 100 ;
unit = " KiB";
} else {
convertedValue = Math.round( bytes );
unit = " B";
}
return convertedValue + unit;
}
</script>