]> git.ktnx.net Git - mpd-feeder.git/commitdiff
working re-connection on disconnection
authorDamyan Ivanov <dmn@debian.org>
Thu, 25 Nov 2021 07:44:11 +0000 (07:44 +0000)
committerDamyan Ivanov <dmn@debian.org>
Thu, 25 Nov 2021 07:44:11 +0000 (07:44 +0000)
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

lib/App/MPD/Feeder.pm

index 942b95429e9b86d6204fb5a6b5e4657e0ccf7aeb..c951c70e8dc6134a7cbdda903042445e43f17d9f 100644 (file)
@@ -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;
     }
 }