<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<style type="text/css">
body { margin: 0; }
.container {
display: flex;
}
.server {
border-spacing: 5px;
background-color: #eee;
border: 1px solid #666;
}
.first-row {
font-weight: bold;
}
.server-ip {
text-align: center;
}
.client-label, .client-speed {
border: 1px solid black;
text-align: center;
}
.client-speed {
width: 240px;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<table v-for="server in servers" class="server">
<tbody>
<tr class="first-row"><td>Server IP:</td><td class="server-ip">{{ server.address }}</td></tr>
<tr><td>Uptime:</td><td>{{ formatSeconds(server.uptime) }}</td></tr>
<tr><td>Upload speed:</td><td>{{ formatBytes(server.uploadSpeed) +'/s' }}</td></tr>
<tr><td>Download speed:</td><td>{{ formatBytes(server.downloadSpeed) +'/s' }}</td></tr>
<tr><td>Total sent:</td><td>{{ formatBytes(server.bytesSent) }}</td></tr>
<tr><td>Total received:</td><td>{{ formatBytes(server.bytesReceived) }}</td></tr>
<tr v-for="client in server.clients">
<td class="client-label">{{ client.address.split( ":" )[0] }}</td>
<td class="client-speed" :style="calcBackgroundStyle(client.uploadSpeed)"><span>{{ formatBytes(client.uploadSpeed) + '/s' }}</span></td>
</tr>
</tbody>
</table>
</div>
</div>
<script src="vue.min.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
data: {},
log: { server: {}, client: {} },
timespan: 120
},
computed: {
servers () {
if (!this.data.servers) return []
const servers = this.data.servers.slice(0)
servers.sort((a, b) => b.clients.length - a.clients.length)
servers.forEach(server => {
this.calcSpeed('server', server)
server.clients.forEach(client => {
this.calcSpeed('client', client, server.timestamp)
})
server.clients = server.clients.filter(client => client.uploadSpeed > 0)
server.clients.sort((a, b) => b.uploadSpeed - a.uploadSpeed)
})
return servers
}
},
methods: {
async updateData () {
const response = await fetch('/data2.json')
this.data = await response.json()
setTimeout(this.updateData, 2000)
},
calcSpeed (type, obj, timestamp) {
var log = this.log[type][obj.address]
log = this.log[type][obj.address] = log ? log.filter(x => x.timestamp > this.data.timestamp - this.timespan * 1000) : []
if (timestamp) obj.timestamp = timestamp
log.push(obj)
if (log.length > 0) {
const a = log[0]
const b = log[log.length - 1]
const time = (b.timestamp - a.timestamp) / 1000
obj.uploadSpeed = (b.bytesSent - a.bytesSent) / time
if (type === 'server') obj.downloadSpeed = (b.bytesReceived - a.bytesReceived) / time
}
},
formatBytes (bytes) {
if (bytes < 1024) return bytes.toFixed(2) + ' Bytes'
else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + ' KiB'
else if (bytes < 1073741824) return (bytes / 1048576).toFixed(2) + ' MiB'
else if (bytes < 1099511627776) return (bytes / 1073741824).toFixed(2) + ' GiB'
else return (bytes / 1099511627776).toFixed(2) + ' TiB'
},
formatSeconds (seconds) {
return ( Math.floor(seconds / ( 3600 * 24 ) ) + 'd '
+ Math.floor(seconds / 3600 ) % 24 + 'h '
+ Math.floor(seconds / 60 ) % 60 + 'min' )
},
calcBackgroundStyle (speed) {
const percent = Math.round(Math.max(0, Math.min(100, Math.log(1 + speed * (100000 / 1073741824)) / Math.log(100000) * 100)))
var color = '#056d00'
if (speed < 1048576) color = '#8adb8b'
else if (speed < 10485760) color = '#5cdb55'
else if (speed < 104857600) color = '#26a81f'
return { background: `linear-gradient(90deg, ${color} ${percent}%, #e0e0e0 ${percent}%)` }
}
},
created () {
const urlParams = new URLSearchParams(window.location.search)
this.timespan = parseInt(urlParams.get('timespan')) || 120
this.updateData()
}
})
</script>
</body>
</html>