diff options
-rwxr-xr-x | capibarra | 289 |
1 files changed, 159 insertions, 130 deletions
@@ -13,7 +13,6 @@ use Time::HiRes qw<gettimeofday>; # Turn off buffering $| = 1; - ################################################################################ # Formatting @@ -32,18 +31,62 @@ sub color_thresholds($x, $warn, $err) { } } -sub pango_warning($txt, $enabled) { - return $enabled ? "<span background='red'>$txt</span>" : $txt; +sub txt_onoff($txt, $on) { + return $on ? $txt : "${txt}X"; } -sub pango_onoff($txt, $on) { - return $on ? $txt : "<span strikethrough='true'>$txt</span>"; -} +################################################################################ +# Profiling -sub txt_onoff($txt, $on) { - return $on ? $txt : "${txt}X"; +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 + +my %MODS; + + +########################################## +# Linux + +my %linux_mods; + +$linux_mods{'CPU'} = { + period => 5, + init => sub { + open(my $loadf, '<', '/proc/loadavg'); + return { state => $loadf }; + }, + compute => sub { + my $loadf = shift; + read($loadf, my $loads, 14); + seek($loadf, 0, 0); + my @loads = split ' ', $loads; + return { + text => sprintf ("CPU %s/%s/%s", @loads), + color => color_thresholds($loads[1], 1, 3), + state => $loadf, + }; + } +}; + +$linux_mods{'MEM'} = { + period => 5, + compute => sub { + my $mused = `free | awk '/^Mem:/ {printf("%d", 100 * (\$3/\$2))}'`; + return { + text => sprintf("MEM %s%%", $mused), + color => color_thresholds($mused, 70, 90), + }; + } +}; + sub render_iface_linux($is_wireless, $name, $status, $addr) { my $extra = $addr ? " $addr" : ''; if ($is_wireless and $status eq 'UP') { @@ -51,49 +94,66 @@ sub render_iface_linux($is_wireless, $name, $status, $addr) { my ($dbm) = `iw dev $name link` =~ /signal: ([0-9-]+ dBm)/; $extra .= ' (' . $ssid . ', ' . $dbm . ')'; } - return pango_onoff($is_wireless ? '๐' : '๐', $status eq 'UP') . $extra; + return txt_onoff($is_wireless ? '๐' : '๐', $status eq 'UP') . $extra; } +$linux_mods{'NET'} = { + 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 { text => join ' | ', map { render_iface_linux(@$_) } @wired, @wireless }; + } +}; - -sub render_iface_openbsd($ifaces, $ifname) { - my $iface = $ifaces->{$ifname}; - my $extra = $iface->{'ip'} ? " $iface->{'ip'}" : ''; - my $is_wireless = exists $iface->{'wifi'}; - my $is_up = $iface->{'up'}; - if ($is_wireless and $is_up) { - $extra .= ' (' . $iface->{'wifi_ssid'} . ', ' . $iface->{'wifi_signal'} . ')'; +$linux_mods{'BAT'} = { + period => 3, + init => sub { + my $BATDIR = glob '/sys/class/power_supply/BAT?'; + open(my $bcapf, '<', "$BATDIR/capacity"); + open(my $bstatf, '<', "$BATDIR/status"); + return { state => [$bcapf, $bstatf] }; + }, + compute => sub { + my $state = shift; + my ($bcapf, $bstatf) = @$state; + my $batlevel = <$bcapf>; + chomp $batlevel; + seek($bcapf, 0, 0); + my $batcharging = <$bstatf> eq "Charging\n" ? 'โก' : ''; + seek($bstatf, 0, 0); + return { + text => sprintf("๐%s%s", $batlevel, $batcharging), + color => color_thresholds(100 - $batlevel, 70, 90), + state => $state, + }; } - return txt_onoff($is_wireless ? '๐ถ' : '๐', $is_up) . $extra; -} +}; +$linux_mods{'AUDIO'} = { + period => 2, + compute => sub { + return { text => sprintf "%s%s", + txt_onoff('๐', do {`~/.local/bin/volctl vol-on`; $? == 0}), + txt_onoff('๐ค', do {`~/.local/bin/volctl mic-on`; $? == 0}) + }; + } +}; -################################################################################ -# Profiling +$MODS{'Linux'} = \%linux_mods; -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"; -} +########################################## +# OpenBSD -################################################################################ -# Modules +my %openbsd_mods; -# open(my $loadf, '<', '/proc/loadavg'); -# my %mod_cpu_linux = ( -# name => 'CPU', -# period => 5, -# compute => sub { -# read($loadf, my $loads, 14); -# seek($loadf, 0, 0); -# return { text => sprintf ("CPU %s/%s/%s", split ' ', $loads) }; -# } -# ); - -my %mod_cpu_openbsd = ( - name => 'CPU', +$openbsd_mods{'CPU'} = { period => 5, compute => sub { my $loads = `sysctl -n vm.loadavg`; @@ -104,19 +164,9 @@ my %mod_cpu_openbsd = ( color => color_thresholds($loads[1], 1, 3), }; } -); - -# my %mod_mem_linux = ( -# name => 'MEMORY', -# period => 5, -# compute => sub { -# my $mused = `free | awk '/^Mem:/ {printf("%d", 100 * (\$3/\$2))}'`; -# return { text => pango_warning(sprintf("MEM %s%%", $mused), $mused > 90) }; -# } -# ); - -my %mod_mem_openbsd = ( - name => 'MEMORY', +}; + +$openbsd_mods{'MEM'} = { period => 5, compute => sub { my $uvmexp = `vmstat -s`; @@ -128,26 +178,19 @@ my %mod_mem_openbsd = ( color => color_thresholds($mused, 70, 90), }; } -); - -# my %mod_net_linux = ( -# 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 { text => join ' | ', map { render_iface_linux(@$_) } @wired, @wireless }; -# } -# ); - -my %mod_net_openbsd = ( - name => 'NETWORK', +}; + +sub render_iface_openbsd($ifaces, $ifname) { + my $iface = $ifaces->{$ifname}; + my $extra = $iface->{'ip'} ? " $iface->{'ip'}" : ''; + my $is_wireless = exists $iface->{'wifi'}; + my $is_up = $iface->{'up'}; + if ($is_wireless and $is_up) { + $extra .= ' (' . $iface->{'wifi_ssid'} . ', ' . $iface->{'wifi_signal'} . ')'; + } + return txt_onoff($is_wireless ? '๐ถ' : '๐', $is_up) . $extra; +} +$openbsd_mods{'NET'} = { period => 4, compute => sub { my @wired = (); @@ -179,36 +222,15 @@ my %mod_net_openbsd = ( push @wired, $ifname; } } - # use Data::Dumper; - # print Dumper(\%ifaces); - # print Dumper(\@wired); - # print Dumper(\@wireless); return { text => join ' ยท ', map { render_iface_openbsd(\%ifaces, $_) } sort(@wired), @wireless }; } -); - -# my $BATDIR = glob '/sys/class/power_supply/BAT?'; -# open(my $bcapf, '<', "$BATDIR/capacity"); -# open(my $bstatf, '<', "$BATDIR/status"); -# my %mod_bat_linux = ( -# name => 'BATTERY', -# period => 3, -# compute => sub { -# my $batlevel = <$bcapf>; -# chomp $batlevel; -# seek($bcapf, 0, 0); -# my $batcharging = <$bstatf> eq "Charging\n" ? 'โก' : ''; -# seek($bstatf, 0, 0); -# return { text => pango_warning(sprintf("๐%s%s", $batlevel, $batcharging), $batlevel < 10) }; -# } -# ); +}; sub obsd_get_sysctl($mib) { my @parts = split(' ', `sysctl -n $mib`); return $parts[0]; } -my %mod_bat_openbsd = ( - name => 'BATTERY', +$openbsd_mods{'BAT'} = { period => 3, compute => sub { my $batcharging = obsd_get_sysctl('hw.sensors.acpibat0.raw0') eq "0" ? 'โก' : ''; @@ -220,21 +242,9 @@ my %mod_bat_openbsd = ( color => color_thresholds(100 - $batlevel, 70, 90) }; } -); - -# my %mod_audio_linux = ( -# name => 'AUDIO', -# period => 2, -# compute => sub { -# return { text => sprintf "%s%s", -# pango_onoff('๐', do {`volctl vol-on`; $? == 0}), -# pango_onoff('๐ค', do {`volctl mic-on`; $? == 0}) -# }; -# } -# ); - -my %mod_audio_openbsd = ( - name => 'AUDIO', +}; + +$openbsd_mods{'AUDIO'} = { period => 2, compute => sub { my $audioinfo = `sndioctl`; @@ -245,24 +255,44 @@ my %mod_audio_openbsd = ( txt_onoff('๐ค', $micmuted == 0) }; } -); +}; + +$MODS{'OpenBSD'} = \%openbsd_mods; -my %mod_date = ( - name => 'DATE', +########################################## +# Common (POSIX) + +my %common_mods; + +$common_mods{'DATE'} = { period => 2, compute => sub { my $date = `date +'%Y-%m-%d %H:%M'`; chomp $date; return { text => $date }; } -); +}; + +$MODS{'_common'} = \%common_mods; ################################################################################ # Main -my @mods = (\%mod_cpu_openbsd, \%mod_mem_openbsd, \%mod_net_openbsd, \%mod_bat_openbsd, \%mod_audio_openbsd, \%mod_date); +my $OS = `uname -s`; +chomp $OS; +my %os_mods = ( %{$MODS{$OS}}, %{$MODS{'_common'}} ); + +my @mods = ('CPU', 'MEM', 'NET', 'BAT', 'AUDIO', 'DATE'); my %cache; +sub render_section($result) { + my $color = $result->{color}; + my $color = $color ? ",\"$color->{type}\":\"$color->{val}\"" : ''; + return sprintf "{\"full_text\":\"%s\",\"separator\":false$color}", $result->{text}; +} + +my $separator = render_section({text => 'ยท'}); + my $profile = 0; foreach my $arg (@ARGV) { if ($arg eq '--profile') { @@ -272,10 +302,10 @@ foreach my $arg (@ARGV) { printf("{ \"version\": 1 }\n[\n"); -sub render_section($result) { - my $color = $result->{color}; - my $color = $color ? ",\"$color->{type}\":\"$color->{val}\"" : ''; - return sprintf "{\"full_text\":\"%s\",\"separator\":false$color}", $result->{text}; +# Call each module's init subroutine +foreach my $modname (@mods) { + my $mod = $os_mods{$modname}; + $cache{$modname} = &{$mod->{init}} if $mod->{init}; } my $counter = 0; @@ -283,21 +313,20 @@ while (1) { my @sections; my (undef, $time0) = gettimeofday() if $profile; - foreach my $mod (@mods) { + foreach my $modname (@mods) { + my $mod = $os_mods{$modname}; my (undef, $time) = gettimeofday() if $profile; - my $result; + my $result = $cache{$modname}; if ($counter % $mod->{period} == 0) { - $result = &{$mod->{compute}}; - $cache{$mod->{name}} = $result; - } else { - $result = $cache{$mod->{name}}; + $result = &{$mod->{compute}}($result->{state}); + $cache{$modname} = $result; } push(@sections, render_section($result)); - show_time_delta($mod->{name}, $time, $counter % $mod->{period} == 0) if $profile; + show_time_delta($modname, $time, $counter % $mod->{period} == 0) if $profile; } show_time_delta('TOTAL', $time0, 0) if $profile; - printf("[%s],\n", join(',{"full_text":"ยท","separator":false},', @sections)); + printf("[%s],\n", join(",$separator,", @sections)); $counter += 1; sleep 1; |