(function () { let app = document.getElementById('app') function httpGet (url) { let request = new XMLHttpRequest() return new Promise(function (resolve, reject) { request.onreadystatechange = function () { if (this.readyState === 4) { if (this.status === 200) { resolve(this.responseText) } else if (this.response == null && this.status === 0) { reject(new Error('The status server appears to be offile.')) } } } request.open("GET", url, true) request.send(null) }) } function bytesToSize (bytes) { let sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'] if (bytes == 0) return '0 Byte' let i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))) return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i] } // Add a zero in front of single-digit numbers function zf (v) { if (v > 9) { return '' + v } else { return '0' + v } } // Convert seconds into years days hours minutes seconds(.milliseconds) function readableTime (timems, ignoreMs) { var time = timems | 0 var ms = ignoreMs ? '' : '.' + zf((timems * 100) % 100 | 0) if (time < 60) return zf(time) + ms + 's' else if (time < 3600) return zf(time / 60 | 0) + 'm ' + zf(time % 60) + ms + 's' else if (time < 86400) return zf(time / 3600 | 0) + 'h ' + zf((time % 3600) / 60 | 0) + 'm ' + zf((time % 3600) % 60) + ms + 's' else if (time < 31536000) return (time / 86400 | 0) + 'd ' + zf((time % 86400) / 3600 | 0) + 'h ' + zf((time % 3600) / 60 | 0) + 'm ' + zf((time % 3600) % 60) + 's' else return (time / 31536000 | 0) + 'y ' + zf((time % 31536000) / 86400 | 0) + 'd ' + zf((time % 86400) / 3600 | 0) + 'h ' + zf((time % 3600) / 60 | 0) + 'm ' + zf((time % 3600) % 60) + 's' } function e (element, content, cl) { let el = document.createElement(element) if (cl) el.className = cl el.innerHTML = content return el.outerHTML } function box (type, content) { return e('div', content, type) } function bar (metric, value, percentage, low, high) { return box('bar-outer', e('span', metric, 'bar-name') + box('bar-inner', '
' ) + box('bar-stats', e('span', low, 'stat-low') + e('span', value, 'stat-now') + e('span', high, 'stat-high') ) ) } function renderPage (data) { let title = 'Welcome to ' + data.hostname + ' on ' + data.kernel document.title = title app.innerHTML = '' app.innerHTML += box('infobox-row', box('general infobox', box('header', e('h2', 'General') ) + box('content', box('row', e('label', 'Hostname') + e('span', data.hostname) ) + box('row', e('label', 'Uptime') + e('span', readableTime(data.uptime)) ) + box('row', e('label', 'Kernel version') + e('span', data.kernel) ) + box('row', e('label', 'Processes') + e('span', data.cpu.processes) ) ) ) + // CPU usage box('cpu infobox', box('header', e('h2', 'CPU') ) + box('content', box('row', e('label', 'Num. cores') + e('span', data.cpu.count) ) + box('row', e('label', 'Usage') + e('span', Math.floor(data.cpu.usage) + ' %') ) + box('row', e('label', 'Load averages') + e('span', data.cpu.loadAverage[0].toFixed(2) + ', ' + data.cpu.loadAverage[1].toFixed(2) + ', ' + data.cpu.loadAverage[2].toFixed(2)) ) ) )) // Memory usage let memuse = (data.memory.total - data.memory.free) app.innerHTML += box('memory infobox', box('header', e('h2', 'Memory') ) + box('content', bar('Memory usage', bytesToSize(memuse), memuse * 100 / data.memory.total, '0 Bytes', bytesToSize(data.memory.total)) ) ) // Network interfaces let interfaces = '' for (let int in data.network) { if (int === 'lo') continue let iface = data.network[int] let ips = [] for (let ip in iface.addresses) { ips.push(e('span', iface.addresses[ip], 'ip-addr')) } interfaces += box('interface', e('h3', int) + ips.join('') + e('h4', 'Bandwidth', 'sec-info') + box('row', e('label', 'Download') + e('span', bytesToSize(iface.download)) ) + box('row', e('label', 'Upload') + e('span', bytesToSize(iface.upload)) ) ) } // Disks let disks = '' for (let mount in data.disk) { let disk = data.disk[mount] disks += box('disk', e('h3', 'Mounted on ' + mount) + box('row', e('label', 'Free space') + e('span', disk.freeGb + ' GB') ) + bar('Disk usage', disk.usedGb + ' GB', disk.usedPercentage, '0 GB', disk.totalGb + ' GB') ) } app.innerHTML += box('infobox-row', box('network infobox', box('header', e('h2', 'Network Interfaces') ) + box('content', box('interfaces', interfaces) ) )+ box('disk infobox', box('header', e('h2', 'Disk Drives') ) + box('content', box('disks', disks) ) ) ) } function update () { httpGet('/status').then(function (data) { try { renderPage(JSON.parse(data)) } catch (e) { console.error(e) } }, function (e) { console.error(e) }) } update() })()