From 055e9c5cda155aefc6c36116899cc5e978d17a5c Mon Sep 17 00:00:00 2001 From: Andrew Lorimer Date: Thu, 6 Jun 2019 18:20:11 +1000 Subject: [PATCH] rewrite i3blocks-bandwidth in perl --- i3blocks-bandwidth.pl | 112 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100755 i3blocks-bandwidth.pl diff --git a/i3blocks-bandwidth.pl b/i3blocks-bandwidth.pl new file mode 100755 index 0000000..c32e0f5 --- /dev/null +++ b/i3blocks-bandwidth.pl @@ -0,0 +1,112 @@ +#!/usr/bin/perl +# +# i3blocks-bandwidth.pl +# +# Get network throughput from /sys/class/net and convert it to readable format. +# Keeps the text at a constant width regardless of the magnitude or units. This +# is useful for i3bar with you don't want widgets changing width, but it could +# also be used for other indicators or just as a quick shell script. +# +# Usage: i3blocks-bandwidth.pl INTERFACE +# test 9198 (can be any float or integer) +# test {1..1000} (using shell expansion) +# +# Note that Perl's printf doesn't round properly for numbers like 0.95 (i.e. +# 0.95 -> 0.9b not 1.0b). However, it is a lot faster than implementing a +# custom rounding function. Accuracy doesn't matter much in this case. Also, +# this script works best with a refresh rate of 1 second. It doesn't have to +# be exact, but larger/smaller values give misleading averages. +# + +use strict; +use warnings; + +my $temppath = "/dev/shm/bandwidth-$ARGV[0]"; + +offline() if ($#ARGV < 0); # fail if no interface is specified + +if ($ARGV[0] eq "test") { # see comment at top of file + shift; + foreach (@ARGV) { + parse($_); + print "\n"; + } + exit; +} + +# Check if interface is up +open(STFILE, "/sys/class/net/$ARGV[0]/operstate") or offline(); +my $state = ; +close (STFILE); +$state =~ m/\A([^:\s]+)/; +offline() if ($1 ne "up"); + +sub offline { + print ""; + print "down"; + print ""; + exit; +} + +# Get rx bytes +open(BYTES, "/sys/class/net/$ARGV[0]/statistics/rx_bytes") or offline(); +my $rx_bytes = ; +close BYTES; +chomp $rx_bytes; + +# Get tx bytes +open(BYTES, "/sys/class/net/$ARGV[0]/statistics/tx_bytes") or offline(); +my $tx_bytes = ; +close (BYTES); +chomp $tx_bytes; + +# Get current time +my $time = time; + +if (-f $temppath) { # Read then overwrite file + open(BYTES, $temppath); + my $oldcontent = ; # read old data + close (BYTES); + open(my $fh, '>', $temppath); + print $fh "$time $rx_bytes $tx_bytes"; # write new data + close $fh; + my ($oldtime, $oldrx, $oldtx) = split / /, $oldcontent; + my $dt = $time - $oldtime; + my $drxdt = ($rx_bytes - $oldrx) / $dt * 8; # *8 converts bytes to bits + my $dtxdt = ($tx_bytes - $oldtx) / $dt * 8; + parse($drxdt); + print " / "; + parse($dtxdt); +} else { # Write data and exit + open(my $fh, '>', $temppath); + print $fh "$time $rx_bytes $tx_bytes"; + close $fh; + chmod 0666, $temppath; + exit; +} + +sub parse { # Determine best units and call round() + my ($val) = @_; + if ($val == 0) { + print "000b"; + } elsif ($val < 999.5) { # bits/second + round($val, "b"); + } elsif ($val < 999500) { # kilobits/second + round($val / 1000, "k"); + } elsif ($val < 999500000) { # megabits/second + round($val / 1000000, "M"); + } else { + round($val / 10000000000, "G"); + } +} + +sub round { # Format to the correct number of characters + my ($val, $suffix) = @_; + if ($val < 9.95) { + printf("%.1f%s", $val, $suffix); # *.* + } elsif ($val < 99.5) { + printf("0%.0f%s", $val, $suffix); # 0** + } else { + printf("%.0f%s", $val, $suffix); # *** + } +} -- 2.47.0