Merge pull request #231 from D9ping/bandwidthmonitoring

Data usage monitoring page
This commit is contained in:
Bill Zimmerman 2018-09-17 10:20:45 +02:00 committed by GitHub
commit c0152612bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 302 additions and 9 deletions

View File

@ -0,0 +1,85 @@
<?php
require_once '../../includes/config.php';
require_once RASPI_CONFIG.'/raspap.php';
session_start();
header('X-Frame-Options: DENY');
header("Content-Security-Policy: default-src 'none'; connect-src 'self'");
require_once '../../includes/authenticate.php';
$interface = filter_input(INPUT_GET, 'inet', FILTER_SANITIZE_SPECIAL_CHARS);
if (empty($interface)) {
// Use first interface if inet parameter not provided.
exec("ip -o link show | awk -F ': ' '{print $2}' | grep -v lo ", $interfacesWlo);
if (count($interfacesWlo) > 0) {
$interface = $interfacesWlo[0];
} else {
exit('No network interfaces found.');
}
}
define('IFNAMSIZ', 16);
if (strlen($interface) > IFNAMSIZ) {
exit('Interface name too long.');
} elseif(!preg_match('/^[a-zA-Z0-9]+$/', $interface)) {
exit('Invalid interface name.');
}
exec(sprintf('vnstat -i %s --json ', escapeshellarg($interface)), $jsonstdoutvnstat,
$exitcodedaily);
if ($exitcodedaily !== 0) {
exit('vnstat error');
}
$jsonobj = json_decode($jsonstdoutvnstat[0], true);
$timeunits = filter_input(INPUT_GET, 'tu');
if ($timeunits === 'm') {
// months
$jsonData = $jsonobj['interfaces'][0]['traffic']['months'];
} else {
// default: days
$jsonData = $jsonobj['interfaces'][0]['traffic']['days'];
}
$datasizeunits = filter_input(INPUT_GET, 'dsu');
header('X-Content-Type-Options: nosniff');
header('Content-Type: application/json');
echo '[ ';
$firstelm = true;
for ($i = count($jsonData) - 1; $i >= 0; --$i) {
if ($timeunits === 'm') {
$dt = DateTime::createFromFormat('Y n', $jsonData[$i]['date']['year'].' '.
$jsonData[$i]['date']['month']);
} else {
$dt = DateTime::createFromFormat('Y n j', $jsonData[$i]['date']['year'].' '.
$jsonData[$i]['date']['month'].' '.
$jsonData[$i]['date']['day']);
}
if ($firstelm) {
$firstelm = false;
} else {
echo ',';
}
if ($datasizeunits == 'mb') {
$datasend = round($jsonData[$i]['tx'] / 1024, 0);
$datareceived = round($jsonData[$i]['rx'] / 1024, 0);
} else {
$datasend = $jsonData[$i]['rx'];
$datareceived = $jsonData[$i]['rx'];
}
if ($timeunits === 'm') {
echo '{ "date": "' , $dt->format('Y-m') , '", "rx": "' , $datareceived ,
'", "tx": "' , $datasend , '" }';
} else {
echo '{ "date": "' , $dt->format('Y-m-d') , '", "rx": "' , $datareceived ,
'", "tx": "' , $datasend , '" }';
}
}
echo ' ]';

View File

@ -6,7 +6,13 @@ $validated = ($user == $config['admin_user']) && password_verify($pass, $config[
if (!$validated) {
header('WWW-Authenticate: Basic realm="RaspAP"');
header('HTTP/1.0 401 Unauthorized');
die ("Not authorized");
if (function_exists('http_response_code')) {
// http_response_code will respond with proper HTTP version back.
http_response_code(401);
} else {
header('HTTP/1.0 401 Unauthorized');
}
exit('Not authorized'.PHP_EOL);
}

View File

@ -26,6 +26,7 @@ define('RASPI_OPENVPN_ENABLED', false );
define('RASPI_TORPROXY_ENABLED', false );
define('RASPI_CONFAUTH_ENABLED', true );
define('RASPI_CHANGETHEME_ENABLED', true );
define('RASPI_VNSTAT_ENABLED', true );
// Locale settings
define('LOCALE_ROOT', 'locale');

91
includes/data_usage.php Normal file
View File

@ -0,0 +1,91 @@
<?php
/**
* Generate html for displaying data usage.
*/
function DisplayDataUsage(&$extraFooterScripts)
{
?>
<div class="row">
<div class="col-lg-12">
<div class="panel panel-primary">
<div class="panel-heading"><i class="fa fa-bar-chart fa-fw"></i> <?php echo _("Data usage monitoring"); ?></div>
<div class="panel-body">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-body">
<ul id="tabbarBandwidth" class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#daily" aria-controls="daily" role="tab" data-toggle="tab"><?php echo _("Daily"); ?></a></li>
<li role="presentation" class=""><a href="#monthly" aria-controls="monthly" role="tab" data-toggle="tab"><?php echo _("Monthly"); ?></a></li>
</ul>
<div id="tabsBandwidth" class="tabcontenttraffic tab-content">
<div role="tabpanel" class="tab-pane active fade in" id="daily">
<div class="row">
<div class="col-lg-12">
<h4><?php echo _('Daily traffic amount'); ?></h4>
<label for="cbxInterfacedaily"><?php echo _('interface'); ?></label>
<select id="cbxInterfacedaily" class="form-control" name="interfacedaily">
<?php
exec("ip -o link show | awk -F ': ' '{print $2}' | grep -v lo ", $interfacesWlo);
foreach ($interfacesWlo as $interface) {
echo ' <option value="' , htmlentities($interface, ENT_QUOTES) , '">' ,
htmlentities($interface, ENT_QUOTES) , '</option>' , PHP_EOL;
}
?>
</select>
<div class="hidden alert alert-info" id="divLoaderBandwidthdaily"><?php
echo sprintf(_("Loading %s bandwidth chart"), _('daily')); ?></div>
<div id="divChartBandwidthdaily"></div>
<div id="divTableBandwidthdaily"></div>
</div>
</div>
</div><!-- /.tab-pane -->
<div role="tabpanel" class="tab-pane fade" id="monthly">
<div class="row">
<div class="col-lg-12">
<h4><?php echo _("Monthly traffic amount"); ?></h4>
<label for="cbxInterfacemonthly"><?php echo _('interface'); ?></label>
<select id="cbxInterfacemonthly" class="form-control" name="interfacemonthly">
<?php
foreach ($interfacesWlo as $interface) {
echo ' <option value="' , htmlentities($interface, ENT_QUOTES) , '">' ,
htmlentities($interface, ENT_QUOTES) , '</option>' , PHP_EOL;
}
?>
</select>
<div class="hidden alert alert-info" id="divLoaderBandwidthmonthly">
<?php echo sprintf(_("Loading %s bandwidth chart"), _('monthly')); ?>
</div>
<div id="divChartBandwidthmonthly"></div>
<div id="divTableBandwidthmonthly"></div>
</div>
</div>
</div><!-- /.tab-pane -->
</div><!-- /.tabsBandwidth -->
</div><!-- /.panel-default -->
</div><!-- /.col-md-6 -->
</div><!-- /.row -->
</div><!-- /.panel-body -->
</div><!-- /.panel-primary -->
<div class="panel-footer"><?php echo _("Information provided by vnstat"); ?></div>
</div><!-- /.panel-primary -->
</div><!-- /.col-lg-12 -->
</div><!-- /.row -->
<script type="text/javascript"<?php //echo ' nonce="'.$csp_page_nonce.'"'; ?>>
// js translations:
var t = new Array();
t['send'] = '<?php echo addslashes(_('Send')); ?>';
t['receive'] = '<?php echo addslashes(_('Receive')); ?>';
</script>
<?php
$extraFooterScripts[] = array('src'=>'vendor/raphael/raphael.min.js',
'defer'=>false);
$extraFooterScripts[] = array('src'=>'vendor/morrisjs/morris.min.js', 'defer'=>false);
$extraFooterScripts[] = array('src'=>'vendor/datatables/js/jquery.dataTables.min.js', 'defer'=>false);
$extraFooterScripts[] = array('src'=>'js/bandwidthcharts.js', 'defer'=>false);
}

View File

@ -33,6 +33,7 @@ include_once( 'includes/system.php' );
include_once( 'includes/configure_client.php' );
include_once( 'includes/networking.php' );
include_once( 'includes/themes.php' );
include_once( 'includes/data_usage.php' );
$output = $return = 0;
$page = $_GET['page'];
@ -155,6 +156,11 @@ $theme_url = 'dist/css/'.htmlspecialchars($theme, ENT_QUOTES);
<a href="index.php?page=theme_conf"><i class="fa fa-wrench fa-fw"></i> <?php echo _("Change Theme"); ?></a>
</li>
<?php endif; ?>
<?php if ( RASPI_VNSTAT_ENABLED ) : ?>
<li>
<a href="index.php?page=data_use"><i class="fa fa-bar-chart fa-fw"></i> <?php echo _("Data usage"); ?></a>
</li>
<?php endif; ?>
<li>
<a href="index.php?page=system_info"><i class="fa fa-cube fa-fw"></i> <?php echo _("System"); ?></a>
</li>
@ -175,6 +181,7 @@ $theme_url = 'dist/css/'.htmlspecialchars($theme, ENT_QUOTES);
</div><!-- /.row -->
<?php
$extraFooterScripts = array();
// handle page actions
switch( $page ) {
case "wlan0_info":
@ -207,13 +214,17 @@ $theme_url = 'dist/css/'.htmlspecialchars($theme, ENT_QUOTES);
case "theme_conf":
DisplayThemeConfig();
break;
case "data_use":
DisplayDataUsage($extraFooterScripts);
break;
case "system_info":
DisplaySystem();
break;
default:
DisplayDashboard();
}
?>
?>
</div><!-- /#page-wrapper -->
</div><!-- /#wrapper -->
@ -229,15 +240,24 @@ $theme_url = 'dist/css/'.htmlspecialchars($theme, ENT_QUOTES);
<!-- Metis Menu Plugin JavaScript -->
<script src="vendor/metisMenu/metisMenu.min.js"></script>
<!-- Morris Charts JavaScript -->
<!--script src="vendor/raphael/raphael-min.js"></script-->
<!--script src="vendor/morrisjs/morris.min.js"></script-->
<!--script src="js/morris-data.js"></script-->
<!-- Custom Theme JavaScript -->
<script src="dist/js/sb-admin-2.js"></script>
<!-- Custom RaspAP JS -->
<script src="js/custom.js"></script>
<?php
// Load non default JS/ECMAScript in footer.
foreach ($extraFooterScripts as $script) {
echo ' <script type="text/javascript" src="' , $script['src'] , '"';
if ($script['defer']) {
echo ' defer="defer"';
}
// if ($script['async']) { echo ( echo ' defer="async"'; ), intrigity=, nonce= etc. etc.
echo '></script>' , PHP_EOL;
}
?>
</body>
</html>

View File

@ -9,7 +9,7 @@ function update_system_packages() {
function install_dependencies() {
install_log "Installing required packages"
sudo apt-get install lighttpd $php_package git hostapd dnsmasq || install_error "Unable to install dependencies"
sudo apt-get install lighttpd $php_package git hostapd dnsmasq vnstat || install_error "Unable to install dependencies"
}
install_raspap

90
js/bandwidthcharts.js Normal file
View File

@ -0,0 +1,90 @@
(function($, _t) {
"use strict";
/**
* Create a Morris.js barchart.
*/
function CreateBarChart(placeholder, datasizeunits) {
var barchart = new Morris.Bar({
element: placeholder,
xkey: 'date',
ykeys: ['rx', 'tx'],
labels: [_t['send']+' '+datasizeunits.toUpperCase(),
_t['receive']+' '+datasizeunits.toUpperCase()]
});
return barchart;
}
/**
* Create a jquery bootstrap datatable.
*/
function CreateDataTable(placeholder, timeunits) {
$("#"+placeholder).append('<table id="tableBandwidth'+timeunits+
'" class="table table-responsive table-striped container-fluid"><thead>'+
'<tr><th>date</th><th>rx</th><th>tx</th></tr></thead><tbody></tbody></table>');
}
/**
* Figure out which tab is selected and remove all existing charts and then
* construct the proper barchart.
*/
function ShowBandwidthChartHandler(e) {
// Remove all morrisjs charts
$('#divChartBandwidthdaily').empty();
$('#divChartBandwidthmonthly').empty();
// Remove all datatables
$('#divTableBandwidthdaily').empty();
$('#divTableBandwidthmonthly').empty();
// Construct ajax uri for getting the proper data.
var timeunit = $('ul#tabbarBandwidth li.active a').attr('href').substr(1);
var uri = 'ajax/bandwidth/get_bandwidth.php?';
uri += 'inet=';
uri += encodeURIComponent($('#cbxInterface'+timeunit+' option:selected').text());
uri += '&tu=';
uri += encodeURIComponent(timeunit.substr(0, 1));
var datasizeunits = 'mb';
uri += '&dsu='+encodeURIComponent(datasizeunits);
// Init. chart
var barchart = CreateBarChart('divChartBandwidth'+timeunit, datasizeunits);
// Init. datatable html
var datatable = CreateDataTable('divTableBandwidth'+timeunit, timeunit);
// Get data for chart
$.ajax({
url: uri,
dataType: 'json',
beforeSend: function() {
$('#divLoaderBandwidth'+timeunit).removeClass('hidden');
}
}).done(function(jsondata) {
$('#divLoaderBandwidth'+timeunit).addClass('hidden');
barchart.setData(jsondata);
$('#tableBandwidth'+timeunit).DataTable({
'searching': false,
'paging': false,
'data': jsondata,
'order': [[ 0, 'ASC' ]],
'columns': [
{ 'data': 'date' },
{ 'data': 'rx', "title": _t['send']+' '+datasizeunits.toUpperCase() },
{ 'data': 'tx', "title": _t['receive']+' '+datasizeunits.toUpperCase() }]
});
}).fail(function(xhr, textStatus) {
if (window.console) {
console.error('server error');
} else {
alert("server error");
}
});
}
$(document).ready(function() {
$('#tabbarBandwidth a[data-toggle="tab"]').on('shown.bs.tab', ShowBandwidthChartHandler);
$('#cbxInterfacedaily').on('change', ShowBandwidthChartHandler);
$('#cbxInterfaceweekly').on('change', ShowBandwidthChartHandler);
$('#cbxInterfacemonthly').on('change', ShowBandwidthChartHandler);
ShowBandwidthChartHandler();
});
})(jQuery, t);