Skip to content
Snippets Groups Projects
Commit e2422adf authored by Roman Lacko's avatar Roman Lacko
Browse files

Module failure and timeouts

parent b7445145
No related branches found
No related tags found
No related merge requests found
...@@ -9,30 +9,41 @@ use feature qw(signatures); ...@@ -9,30 +9,41 @@ use feature qw(signatures);
no warnings qw(experimental::signatures); no warnings qw(experimental::signatures);
use Breeze::Counter; use Breeze::Counter;
use Breeze::Logger;
use Data::Dumper; use Data::Dumper;
sub new($class, %args) { sub new($class, %args) {
return bless { return bless {
storage => {}, storage => {},
log => Breeze::Logger->new("Breeze::Cache"),
}, $class; }, $class;
} }
sub log($self) { return $self->{log}; }
sub set_logger($self, $logger) {
$self->{log} = $logger;
}
sub get($self, $key) { sub get($self, $key) {
my $entry = $self->{storage}->{$key}; my $entry = $self->{storage}->{$key};
return unless defined $entry; return unless defined $entry;
# if entry was zero, the key expired, delete it and move on # if entry was zero, the key expired, delete it and move on
if (!$entry->[0]--) { if (!$entry->[0]--) {
$self->log->debug("cached key for '", $key, "' expired upon request");
delete $self->{storage}->{$key}; delete $self->{storage}->{$key};
return; return;
} }
$self->log->debug("returning cached value for '", $key, "'");
return { $entry->[1]->%* }; return { $entry->[1]->%* };
} }
sub set($self, $key, $value, $recall = 1) { sub set($self, $key, $value, $recall = 1) {
return if exists $self->{storage}->{$key}; return if exists $self->{storage}->{$key};
$self->log->debug("setting a new entry for '", $key, "'");
$self->{storage}->{$key} = [ $self->{storage}->{$key} = [
Breeze::Counter->new(current => $recall), Breeze::Counter->new(current => $recall),
{ %$value }, { %$value },
...@@ -45,9 +56,11 @@ sub set($self, $key, $value, $recall = 1) { ...@@ -45,9 +56,11 @@ sub set($self, $key, $value, $recall = 1) {
sub flush($self, @keys) { sub flush($self, @keys) {
# on total flush, just recreate storage # on total flush, just recreate storage
if (!@keys) { if (!@keys) {
$self->log->debug("flushing all entries");
$self->{storage} = {}; $self->{storage} = {};
# delete selected keys # delete selected keys
} else { } else {
$self->log->debug("flushing keys '", join(",", @keys), "'");
delete $self->{storage}->@{@keys}; delete $self->{storage}->@{@keys};
} }
} }
......
...@@ -17,6 +17,7 @@ use Carp; ...@@ -17,6 +17,7 @@ use Carp;
use Data::Dumper; use Data::Dumper;
use JSON::XS; use JSON::XS;
use Module::Load; use Module::Load;
use Time::HiRes;
use Time::Out qw(timeout); use Time::Out qw(timeout);
use Try::Tiny; use Try::Tiny;
...@@ -32,6 +33,9 @@ sub new($class, $config) { ...@@ -32,6 +33,9 @@ sub new($class, $config) {
$self->init_logger; $self->init_logger;
$self->init_modules; $self->init_modules;
$self->init_events; $self->init_events;
$self->cache->set_logger($self->log->clone(category => "Breeze::Cache"));
return $self; return $self;
} }
...@@ -56,6 +60,8 @@ sub validate($self) { ...@@ -56,6 +60,8 @@ sub validate($self) {
unless $self->cfg->{timeouts} > 0; unless $self->cfg->{timeouts} > 0;
croak "failures is not greater than zero" croak "failures is not greater than zero"
unless $self->cfg->{failures} > 0; unless $self->cfg->{failures} > 0;
croak "cooldown is not greater than zero"
unless $self->cfg->{cooldown} > 0;
} }
# replace utf8 hardcoded string # replace utf8 hardcoded string
...@@ -81,6 +87,7 @@ sub get_or_set_timer($self, $key, $timer, $ticks) { ...@@ -81,6 +87,7 @@ sub get_or_set_timer($self, $key, $timer, $ticks) {
} }
sub delete_timer($self, $key, $timer) { sub delete_timer($self, $key, $timer) {
$self->log->info("removing timer '$timer' for key '$key'");
delete $self->mod($key)->{tmrs}->{$timer}; delete $self->mod($key)->{tmrs}->{$timer};
} }
...@@ -175,6 +182,7 @@ sub init_modules($self) { ...@@ -175,6 +182,7 @@ sub init_modules($self) {
my $entry = { my $entry = {
conf => $modcfg, conf => $modcfg,
mod => $module, mod => $module,
log => $modlog,
tmrs => { tmrs => {
timeout => Breeze::Counter->new(%counterconf, timeout => Breeze::Counter->new(%counterconf,
current => $self->cfg->{timeouts}, current => $self->cfg->{timeouts},
...@@ -208,6 +216,30 @@ sub init_events($self) { ...@@ -208,6 +216,30 @@ sub init_events($self) {
]; ];
} }
sub fail_module($self, $entry, $timer) {
my $tmr = \$entry->{tmrs}->{$timer};
if (!($$tmr--)->current) {
$self->log->error("module depleted timer '$timer' for the last time, disabling");
$entry->{mod} = WBM::Fail->new(
-entry => $entry->{conf}->{-name},
-log => $entry->{log},
text => "$entry->{conf}->{-name}($entry->{conf}->{-driver})",
);
return $entry->{mod}->invoke;
} else {
# temporarily disable module
return {
text => "$entry->{conf}->{-name}($entry->{conf}->{-driver})",
blink => $self->cfg->{cooldown},
cache => $self->cfg->{cooldown},
background => "b58900",
color => "002b36",
icon => ($timer eq "fail" ? "" : ""),
};
}
}
sub run($self) { sub run($self) {
my $ret = []; my $ret = [];
...@@ -235,14 +267,14 @@ sub run($self) { ...@@ -235,14 +267,14 @@ sub run($self) {
# module timeouted? # module timeouted?
if ($@) { if ($@) {
$data = $self->timeout_module($entry); $data = $self->fail_module($entry, "timeout");
# module failed? # module failed?
} elsif (!defined $data) { } elsif (!defined $data) {
$data = $self->fail_module($entry); $data = $self->fail_module($entry, "fail");
} }
} else { } else {
# ignore cached 'blink', 'invert', 'reset_blink' and 'reset_invert' # ignore cached 'blink', 'invert', 'reset_blink' and 'reset_invert'
delete $data->@{qw(blink invert cache)}; delete $data->@{qw(blink invert cache reset_blink reset_invert reset_all)};
} }
# set entry and instance # set entry and instance
...@@ -295,7 +327,7 @@ sub post_process_inversion($self, $ret) { ...@@ -295,7 +327,7 @@ sub post_process_inversion($self, $ret) {
# separators are not supposed to blink # separators are not supposed to blink
next if exists $seg->{separator}; next if exists $seg->{separator};
$self->delete_time($seg->{entry}, "invert") $self->delete_timer($seg->{entry}, "invert")
if $seg->{reset_invert} || $seg->{reset_all}; if $seg->{reset_invert} || $seg->{reset_all};
my $timer = $self->get_or_set_timer($seg->{entry}, "invert", $seg->{invert}); my $timer = $self->get_or_set_timer($seg->{entry}, "invert", $seg->{invert});
...@@ -317,7 +349,7 @@ sub post_process_blinking($self, $ret) { ...@@ -317,7 +349,7 @@ sub post_process_blinking($self, $ret) {
# separators are not supposed to blink # separators are not supposed to blink
next if exists $seg->{separator}; next if exists $seg->{separator};
$self->delete_time($seg->{entry}, "blink") $self->delete_timer($seg->{entry}, "blink")
if $seg->{reset_blink} || $seg->{reset_all}; if $seg->{reset_blink} || $seg->{reset_all};
my $timer = $self->get_or_set_timer($seg->{entry}, "blink", $seg->{blink}); my $timer = $self->get_or_set_timer($seg->{entry}, "blink", $seg->{blink});
...@@ -470,6 +502,10 @@ sub event($self, $event) { ...@@ -470,6 +502,10 @@ sub event($self, $event) {
my $button = $self->event_button($event->{button}); my $button = $self->event_button($event->{button});
my $data = try { my $data = try {
if ($mod->{mod}->refresh_on_event) {
$self->cache->flush($mod->{conf}->{-name});
}
if (!defined $button) { if (!defined $button) {
$self->log->error("got unknown event '$event->{button}' for '$event->{entry}'"); $self->log->error("got unknown event '$event->{button}' for '$event->{entry}'");
return $mod->{mod}->on_event; return $mod->{mod}->on_event;
...@@ -483,8 +519,10 @@ sub event($self, $event) { ...@@ -483,8 +519,10 @@ sub event($self, $event) {
$self->log->error($_); $self->log->error($_);
}; };
if (defined $data) { if (defined $data and ref $data eq "HASH") {
$self->process_event($mod, $data); $self->process_event($mod, $data);
} elsif (defined $data) {
$self->log->debug("event returned ref '", ref($data), "', ignoring");
} }
} }
......
...@@ -9,6 +9,7 @@ use feature qw(signatures); ...@@ -9,6 +9,7 @@ use feature qw(signatures);
no warnings qw(experimental::signatures); no warnings qw(experimental::signatures);
use Carp; use Carp;
use IO::Handle;
use Time::Format qw(%strftime); use Time::Format qw(%strftime);
sub new($class, @args) { sub new($class, @args) {
...@@ -20,6 +21,7 @@ sub new($class, @args) { ...@@ -20,6 +21,7 @@ sub new($class, @args) {
open $self->{fh}, ">:encoding(utf-8)", $self->{filename} open $self->{fh}, ">:encoding(utf-8)", $self->{filename}
or croak "$self->{filename}: $!"; or croak "$self->{filename}: $!";
$self->{fh}->autoflush(1);
$self->info("logging started"); $self->info("logging started");
return $self; return $self;
} }
...@@ -44,4 +46,6 @@ sub debug($self, @msg) { ...@@ -44,4 +46,6 @@ sub debug($self, @msg) {
$self->time, $self->{category}, join("", @msg); $self->time, $self->{category}, join("", @msg);
} }
# vim: syntax=perl5-24
1; 1;
...@@ -21,11 +21,9 @@ sub new($class, %args) { ...@@ -21,11 +21,9 @@ sub new($class, %args) {
} }
sub refresh_on_event($self) { 1; } sub refresh_on_event($self) { 1; }
sub on_left_click($self) { $self->{dismissed} = 1; }
sub on_middle_click($self) { $self->{dismissed} = 1; }
sub on_right_click($self) { $self->{dismissed} = 1; }
sub invoke($self) { sub invoke($self) {
$self->log->info("invoked");
my $ret = { my $ret = {
text => $self->{text}, text => $self->{text},
icon => "", icon => "",
...@@ -34,12 +32,11 @@ sub invoke($self) { ...@@ -34,12 +32,11 @@ sub invoke($self) {
}; };
if ($self->{first}) { if ($self->{first}) {
$ret->{blink} = 6; $ret->{blink} = 30;
$self->{first} = 0;
}
if (!$self->{dismissed}) {
$ret->{invert} = "+inf"; $ret->{invert} = "+inf";
$self->{first} = 0;
} else {
$ret->{reset_all} = 1;
} }
return $ret; return $ret;
......
...@@ -53,40 +53,41 @@ sub run3opt($self) { ...@@ -53,40 +53,41 @@ sub run3opt($self) {
sub run_command($self, @cmd) { sub run_command($self, @cmd) {
my ($stdout, $stderr) = ("",""); my ($stdout, $stderr) = ("","");
if (!run3 \@cmd, \undef, \$stdout, \$stderr, $self->run3opt) { if (!run3(\@cmd, \undef, \$stdout, \$stderr, $self->run3opt) || $?) {
chomp($stdout, $stderr); # some fucked up commands, like pamixer, output \n\n after the command.
$self->log->info("when running '", join(" ", @cmd), "'"); $stdout =~ s/(^\s*|\s*$)//g;
$stderr =~ s/(^\s*|\s*$)//g;
#$self->log->info("when running '", join(" ", @cmd), "'");
if ($? == -1) { if ($? == -1) {
$self->log->error("system command failed: errno=$!"); $self->log->error("system command failed: errno=$!");
$self->log->fatal("this is a fatal error");
} elsif ($? & 127) { } elsif ($? & 127) {
$self->log->error("command died on signal: signo=$?, ", $self->log->error("command died on signal: signo=$?, ",
"stdout='$stdout', stderr='$stderr'"); "stdout='$stdout', stderr='$stderr'");
$self->log->fatal("this is a fatal error");
} elsif ($? >> 8) { } elsif ($? >> 8) {
$self->log->error("command failed: status=", ($? >> 8), ", ", # $self->log->error("command failed: status=", ($? >> 8), ", ",
"stdout= $stdout', stderr='$stderr'"); # "stdout='$stdout', stderr='$stderr'");
} else {
$self->log->error("command succeeded (wtf?): stdout='$stdout', ",
"stderr='$stderr'");
} }
$self->log->fatal("this is a fatal error");
} }
my $status = $?;
# IPC::Run3 does not restore encoding layers # IPC::Run3 does not restore encoding layers
# https://rt.cpan.org/Public/Bug/Display.html?id=69011 # https://rt.cpan.org/Public/Bug/Display.html?id=69011
binmode STDIN; binmode STDIN, ":encoding(utf-8)"; binmode STDIN; binmode STDIN, ":encoding(utf-8)";
binmode STDOUT; binmode STDOUT, ":encoding(utf-8)"; binmode STDOUT; binmode STDOUT, ":encoding(utf-8)";
binmode STDERR; binmode STDOUT, ":encoding(utf-8)"; binmode STDERR; binmode STDOUT, ":encoding(utf-8)";
chomp($stdout, $stderr); $stdout =~ s/(^\s*|\s*$)//g;
$stderr =~ s/(^\s*|\s*$)//g;
if ($stderr ne "") { if ($stderr ne "") {
$self->log->info("while running '", join(" ", @cmd), "'"); $self->log->info("while running '", join(" ", @cmd), "'");
$self->log->error("stderr='$stderr'"); $self->log->error("stderr='$stderr'");
} }
return $stdout; return ($stdout, $stderr, $status);
} }
sub run_pamixer($self, @args) { sub run_pamixer($self, @args) {
...@@ -96,8 +97,10 @@ sub run_pamixer($self, @args) { ...@@ -96,8 +97,10 @@ sub run_pamixer($self, @args) {
sub refresh_on_event($) { 1; } sub refresh_on_event($) { 1; }
sub invoke($self) { sub invoke($self) {
my $muted = $self->run_pamixer("--get-mute") eq "true"; my ($muted, undef, undef) = $self->run_pamixer("--get-mute");
my $volume = $self->run_pamixer("--get-volume"); my ($volume, undef, undef) = $self->run_pamixer("--get-volume");
$muted = ($muted eq "true");
my $ret; my $ret;
if ($muted) { if ($muted) {
......
...@@ -27,6 +27,10 @@ sub new($class, %args) { ...@@ -27,6 +27,10 @@ sub new($class, %args) {
} }
sub invoke($self) { sub invoke($self) {
if (rand(100) < 30) {
sleep 60;
}
return { return {
text => $strftime{$self->{format}, localtime}, text => $strftime{$self->{format}, localtime},
icon => $self->{icon}, icon => $self->{icon},
......
...@@ -44,6 +44,12 @@ timeouts: 3 ...@@ -44,6 +44,12 @@ timeouts: 3
# Values: positive integers # Values: positive integers
failures: 3 failures: 3
# Number of ticks to wait after trying to invoke module again. Until then,
# a warning component will be displayed instead.
#
# Values: positive integers
cooldown: 3
# Spaces to add around full_text entries. # Spaces to add around full_text entries.
# #
# Values: non-negative integers # Values: non-negative integers
...@@ -66,10 +72,14 @@ modules: ...@@ -66,10 +72,14 @@ modules:
- -name: volume - -name: volume
-driver: WBM::PAMixer -driver: WBM::PAMixer
-refresh: 0 -refresh: 0
sink: alsa_output.pci-0000_00_1b.0.analog-stereo sink: alsa_output.pci-0000_00_1f.3.analog-stereo
allow-boost: yes allow-boost: yes
step: 2 step: 2
- separator - separator
- -name: fail
-driver: WBM::Fail
text: "FUCK"
- separator
- -name: time - -name: time
-driver: WBM::Time -driver: WBM::Time
-refresh: 0 -refresh: 0
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment