From: Damyan Ivanov Date: Thu, 25 Nov 2021 07:44:11 +0000 (+0000) Subject: working re-connection on disconnection X-Git-Url: https://git.ktnx.net/?p=mpd-feeder.git;a=commitdiff_plain;h=75314ca2df940801910e9fb045db5fb15ac87f93 working re-connection on disconnection it is not enough to cancel the idle future and then re-connect. Net::Async::MPD is just not suited for such a scenario due to its internal state not refrecting the loss of connection so, upon disconnect, abandon the N:A:MPD instance and create a new one --- diff --git a/lib/App/MPD/Feeder.pm b/lib/App/MPD/Feeder.pm index 942b954..c951c70 100644 --- a/lib/App/MPD/Feeder.pm +++ b/lib/App/MPD/Feeder.pm @@ -10,11 +10,13 @@ use DBD::Pg; use DBI; use Getopt::Long; use IO::Async::Signal; +use IO::Async::Timer::Countdown; use IO::Async::Timer::Periodic; use Log::Any qw($log); use Net::Async::MPD; use Object::Pad; use Syntax::Keyword::Try; +use Time::Duration qw(duration_exact); has $cfg_file :reader; has $opt :reader; @@ -70,9 +72,12 @@ method init_mpd { $mpd->on( close => sub { + $log->warn("Connection to MPD lost"); $mpd->loop->stop('disconnected'); $mpd_connected = 0; - $log->warn("Connection to MPD lost"); + $idler->cancel if $idler; + undef $mpd; + $self->init_mpd; } ); $mpd->on( @@ -266,9 +271,14 @@ method reexec { method break_idle { if ( $idler && !$idler->is_ready ) { - $log->trace("hand-sending 'noidle'"); - undef $idler; - $mpd->{mpd_handle}->write("noidle\n"); + if ($mpd_connected) { + $log->trace("hand-sending 'noidle'"); + undef $idler; + $mpd->{mpd_handle}->write("noidle\n"); + } + else { + $log->trace("not connected to MPD: skipping 'noidle'"); + } } else { $log->trace("no idler found"); @@ -276,7 +286,7 @@ method break_idle { } method sleep_before_reconnection { - $self->debug( "Waiting for " + $log->debug( "Waiting for " . duration_exact($reconnect_delay) . " before re-connecting" ); @@ -294,15 +304,24 @@ method sleep_before_reconnection { method pulse { unless ($mpd_connected) { - $mpd->connect->then( - sub { - $mpd_connected = 1; - $playlist_needs_filling = 1; - $reconnect_delay = $opt->initial_reconnect_delay; - } - )->get; + $log->trace("Connecting to MPD..."); + my $f = $mpd->connect->await; + + if ( $f->is_done ) { + $mpd_connected = 1; + $playlist_needs_filling = 1; + $reconnect_delay = $opt->initial_reconnect_delay; + $mpd->loop->later( sub { $self->pulse } ); + } + elsif ( $f->is_failed ) { + $mpd->loop->stop('disconnected'); + $log->warn($f->failure); + $self->sleep_before_reconnection; + } + else { + die "connect Future neither done nor failed!?"; + } - $mpd->loop->later( sub { $self->pulse } ); return; } @@ -321,17 +340,29 @@ method pulse { $log->debug("Waiting idle. PID=$$"); $last_mpd_comm = time; $idler = $mpd->send("idle database playlist"); - my $result = $idler->get; - undef $idler; + $idler->await; - if ( ref $result and $result->{changed} ) { - my $changed = $result->{changed}; - $changed = [$changed] unless ref $changed; + $log->trace('got out of idle'); - $mpd->emit($_) for @$changed; + if ( $idler->is_done ) { + my $result = $idler->get; + undef $idler; + if ( ref $result and $result->{changed} ) { + my $changed = $result->{changed}; + $changed = [$changed] unless ref $changed; + + $mpd->emit($_) for @$changed; + } + } + elsif ( $idler->is_cancelled ) { + $log->trace("idle was cancelled"); + undef $idler; + } + elsif ( $idler->is_failed ) { + $log->warn("idle failed: ".$idler->failure); + undef $idler; } - $log->trace('got out of idle'); $mpd->loop->stop; } @@ -366,12 +397,6 @@ method run_loop { ); for ( ;; ) { - $mpd->loop->later( sub { $self->pulse } ); - - $log->trace('About to run the loop'); - - $mpd->loop->run; - if ( $quit_requested ) { $log->trace("about to quit"); undef $mpd; @@ -382,10 +407,12 @@ method run_loop { $self->reexec; die "Not reached"; } - elsif ( !$mpd_connected ) { - $self->sleep_before_reconnection; - next; - } + + $log->trace('About to run the loop'); + + $mpd->loop->later( sub { $self->pulse } ); + + $mpd->loop->run; } }