#!/usr/bin/env perl use strict; use warnings; use feature 'signatures'; use Time::HiRes qw; # Turn off buffering $| = 1; ################################################################################ # Formatting sub pango_warning($txt, $enabled) { return $enabled ? "$txt" : $txt; } sub pango_onoff($txt, $on) { return $on ? $txt : "$txt"; } sub render_iface($is_wireless, $name, $status, $addr) { my $extra = ''; $extra .= " $addr" if $addr; if ($is_wireless) { my ($ssid) = `iw dev $name link` =~ /SSID: ([^\n]*).*/; my ($dbm) = `iw dev $name link` =~ /signal: ([0-9-]+ dBm)/; $extra .= ' (' . $ssid . ', ' . $dbm . ')'; } return pango_onoff($is_wireless eq 1 ? '๐Ÿ›œ' : '๐ŸŒ', $status eq 'UP') . $extra; } ################################################################################ # Profiling sub show_time_delta($section, $time0, $computed) { my (undef, $time) = gettimeofday(); my $diff = ($time - $time0) / 1000; my $extra = $computed ? ' (COMPUTED)' : ''; printf STDERR "Spent $diff milliseconds @ $section$extra\n"; } ################################################################################ # Modules open(my $loadf, '<', '/proc/loadavg'); my %mod_cpu = ( name => 'CPU', period => 5, compute => sub { read($loadf, my $loads, 14); seek($loadf, 0, 0); return sprintf ("CPU %s/%s/%s", split ' ', $loads); } ); my %mod_mem = ( name => 'MEMORY', period => 5, compute => sub { my $mused = `free | awk '/^Mem:/ {printf("%d", 100 * (\$3/\$2))}'`; return pango_warning(sprintf("MEM %s%%", $mused), $mused > 90); } ); my %mod_net = ( name => 'NETWORK', period => 4, compute => sub { my @wired = (); my @wireless = (); for (split("\n", `ip --br a`)) { next if substr($_, 0, 2) eq 'lo'; # prevent regex my ($if, $status, $addr) = $_ =~ /^(\S+)\s+(\S+)(?:\s+(\S+))?/; push @wired, [0, $if, $status, $addr] if (substr($if, 0, 2) eq 'en'); push @wireless, [1, $if, $status, $addr] if (substr($if, 0, 2) eq 'wl'); } return join ' | ', map { render_iface(@$_) } @wired, @wireless; } ); my $BATDIR = glob '/sys/class/power_supply/BAT?'; open(my $bcapf, '<', "$BATDIR/capacity"); open(my $bstatf, '<', "$BATDIR/status"); my %mod_bat = ( name => 'BATTERY', period => 3, compute => sub { my $batcharging = <$bstatf> eq "Charging\n" ? 'โšก' : ''; seek($bstatf, 0, 0); my $batlevel = <$bcapf>; chomp $batlevel; seek($bcapf, 0, 0); return pango_warning(sprintf("๐Ÿ”‹%s%s", $batlevel, $batcharging), $batlevel < 10); } ); my %mod_audio = ( name => 'AUDIO', period => 2, compute => sub { return sprintf "%s%s", pango_onoff('๐Ÿ”Š', do {`volctl vol-on`; $? == 0}), pango_onoff('๐ŸŽค', do {`volctl mic-on`; $? == 0}); } ); my %mod_date = ( name => 'DATE', period => 2, compute => sub { my $date = `date +'%Y-%m-%d %H:%M'`; chomp $date; return $date; } ); ################################################################################ # Main my @mods = (\%mod_cpu, \%mod_mem, \%mod_net, \%mod_bat, \%mod_audio, \%mod_date); my %cache; my $profile = 0; foreach my $arg (@ARGV) { if ($arg eq '--profile') { $profile = 1; } } my $counter = 0; while (1) { my @sections; my (undef, $time0) = gettimeofday() if $profile; foreach my $mod (@mods) { my (undef, $time) = gettimeofday() if $profile; my $result; if ($counter % $mod->{period} == 0) { $result = &{$mod->{compute}}; $cache{$mod->{name}} = $result; } else { $result = $cache{$mod->{name}}; } push(@sections, $result); show_time_delta($mod->{name}, $time, $counter % $mod->{period} == 0) if $profile; } show_time_delta('TOTAL', $time0, 0) if $profile; printf("%s\n", join(' ยท ', @sections)); $counter += 1; sleep 1; } # vim: set sw=4