bin/disorder-notify: Stop reading when we reach end-of-file.
[profile] / bin / disorder-notify
index b2967e2..49e83f0 100755 (executable)
@@ -124,8 +124,16 @@ sub get_state0 ($) {
   return \%st;
 }
 
+my $CONF = undef;
+
+sub configured_connection (;$) {
+  my ($quietp) = @_;
+  $CONF //= load_config $C{config};
+  return connect_to_server %$CONF, $quietp // 0;
+}
+
 sub get_state () {
-  my $sk = connect_to_server $C{config};
+  my $sk = configured_connection;
   send_command0 $sk, "log";
   my $st = get_state0 $sk;
   close $sk;
@@ -173,8 +181,8 @@ sub get_now_playing ($) {
 sub watch_and_notify0 ($) {
   my ($now_playing) = @_;
 
-  my $sk = connect_to_server $C{config}, 1;
-  my $sk_log = connect_to_server $C{config}, 1;
+  my $sk = configured_connection 1;
+  my $sk_log = configured_connection 1;
 
   send_command0 $sk_log, "log";
   my $st = get_state0 $sk_log;
@@ -187,42 +195,68 @@ sub watch_and_notify0 ($) {
     notify "$TITLE: Now playing", format_now_playing %$info;
   }
 
-  while (my $line = readline $sk_log) {
-    my @f = split_fields $line;
-
-    if ($f[1] eq "state") {
-      my $msg = undef;
-      if ($f[2] eq "disable_random") { $msg = "Random play disabled"; }
-      elsif ($f[2] eq "enable_random") { $msg = "Random play enabled"; }
-      elsif ($f[2] eq "disable_play") { $msg = "Playing disabled"; }
-      elsif ($f[2] eq "enable_play") { $msg = "Playing enabled"; }
-      elsif ($f[2] eq "pause") { $msg = "Paused"; }
-      elsif ($f[2] eq "resume") { $msg = "Playing"; }
-      notify "$TITLE state", $msg if defined $msg;
-    } elsif ($f[1] eq "playing") {
-      my %info;
-      $info{track} = $f[2];
-      $info{submitter} = $f[3] if @f > 3;
-      decode_track_name $sk, %info;
-      notify "$TITLE: Now playing", format_now_playing %info;
-    } elsif ($f[1] eq "scratched") {
-      my %info;
-      $info{track} = $f[2];
-      decode_track_name $sk, %info;
-      notify "$TITLE: Scratched by $f[3]", format_now_playing %info;
+  fcntl $sk_log, F_SETFL, (fcntl $sk_log, F_GETFL, 0) | O_NONBLOCK;
+  my $buffer = "";
+  my @lines = ();
+  my $rdin = ""; vec($rdin, (fileno $sk_log), 1) = 1;
+  my $loss;
+
+  WATCH: for (;;) {
+    for my $line (@lines) {
+      my @f = split_fields $line;
+      if ($f[1] eq "state") {
+       my $msg = undef;
+       if ($f[2] eq "disable_random") { $msg = "Random play disabled"; }
+       elsif ($f[2] eq "enable_random") { $msg = "Random play enabled"; }
+       elsif ($f[2] eq "disable_play") { $msg = "Playing disabled"; }
+       elsif ($f[2] eq "enable_play") { $msg = "Playing enabled"; }
+       elsif ($f[2] eq "pause") { $msg = "Paused"; }
+       elsif ($f[2] eq "resume") { $msg = "Playing"; }
+       notify "$TITLE state", $msg if defined $msg;
+      } elsif ($f[1] eq "playing") {
+       my %info;
+       $info{track} = $f[2];
+       $info{submitter} = $f[3] if @f > 3;
+       decode_track_name $sk, %info;
+       notify "$TITLE: Now playing", format_now_playing %info;
+      } elsif ($f[1] eq "scratched") {
+       my %info;
+       $info{track} = $f[2];
+       decode_track_name $sk, %info;
+       notify "$TITLE: Scratched by $f[3]", format_now_playing %info;
+      }
+    }
+
+    if (!$sk_log) { $loss = "EOF from server"; last WATCH; }
+    my $nfd = select my $rdout = $rdin, undef, undef, 60;
+    if (!$nfd) {
+      eval { print $sk_log "."; flush $sk_log; };
+      if ($@) { $loss = "error from write: " . $@->errno; last WATCH; }
+      @lines = ();
+    } else {
+      READ: for (;;) {
+       my ($b, $n);
+       eval { $n = sysread $sk_log, $b, 4096; };
+       if ($@ && $@->errno == EAGAIN) { last READ; }
+       elsif ($@) { $loss = "error from read: " . $@->errno; last WATCH; }
+       elsif (!$n) { close $sk_log; $sk_log = undef; last READ; }
+       else { $buffer .= $b; }
+      }
+
+      @lines = split /\n/, $buffer, -1;
+      $buffer = pop @lines;
     }
   }
 
-  notify "$TITLE state", "Lost connection";
+  notify "$TITLE state", "Lost connection: $loss";
 
   close $sk;
-  close $sk_log;
+  close $sk_log if defined $sk_log;
 }
 
 sub watch_and_notify ($) {
   my ($now_playing) = @_;
 
-  fork and exit 0;
   claim_lock or exit 1;
 
   for (;;) {
@@ -243,14 +277,14 @@ $OP{"volume-down"} =
   sub { run_discard_output "amixer", "sset", $C{mixer}, "5\%-"; };
 
 $OP{"scratch"} = sub {
-  my $sk = connect_to_server $C{config};
+  my $sk = configured_connection;
   send_command $sk, "scratch";
   close $sk;
 };
 
 $OP{"enable/disable"} = sub {
   my $st = get_state;
-  my $sk = connect_to_server $C{config};
+  my $sk =configured_connection;
   if ($st->{play}) { send_command $sk, "disable"; }
   else { send_command $sk, "enable"; }
   close $sk;
@@ -258,7 +292,7 @@ $OP{"enable/disable"} = sub {
 
 $OP{"play/pause"} = sub {
   my $st = get_state;
-  my $sk = connect_to_server $C{config};
+  my $sk = configured_connection;
   if (!$st->{play}) {
     send_command $sk, "enable";
     if ($st->{pause}) { send_command $sk, "resume"; }
@@ -278,7 +312,7 @@ $OP{"watch"} = sub {
 };
 
 $OP{"now-playing"} = sub {
-  my $sk = connect_to_server $C{config};
+  my $sk = configured_connection;
   my $info = get_now_playing $sk;
   close $sk;
   print format_now_playing %$info;
@@ -286,11 +320,14 @@ $OP{"now-playing"} = sub {
 };
 
 $OP{"notify-now-playing"} = sub {
-  my $sk = connect_to_server $C{config};
+  my $sk = configured_connection;
   my $info = get_now_playing $sk;
   close $sk;
   notify "$TITLE: Now playing", format_now_playing %$info;
-  defined locked_by or watch_and_notify 0;
+  unless (defined locked_by) {
+    fork and exit 0;
+    watch_and_notify 0;
+  }
 };
 
 $OP{"next-config"} = sub {