Search code examples
perliowaitscreensaver

perl: can I wait 15 minutes, and then if a key has not been pressed, do something?


here's my first ever perl program:

I want to make sure that if I'm away from my machine for a while, then this script ssh's to our main server and kills all my processes there. (I keep forgetting to kill them when I go for lunch and they hog vast amounts of cpu and memory).

I've got this far, and 15 minutes after the screensaver activates the killing starts.

#!/usr/bin/perl

my $cmd = "dbus-monitor --session \"type='signal',interface='org.gnome.ScreenSaver',member='ActiveChanged'\"";

open (IN, "$cmd |");

while (<IN>) {
    if (m/^\s+boolean true/) {
        print "*** Screensaver is active ***\n";
        print "*** Sleeping before megadeath....\n";
        sleep(15*60);
        print "*** killing all jla processes on anvil...\n";
        $result = `ssh anvil pkill -u jla`;
        print "*** should all be dead\n";
        print $result;

    } elsif (m/^\s+boolean false/) {
        print "*** Screensaver is no longer active ***\n";
    }
}

But what I'd like is to wait 15 minutes while monitoring the keyboard. If say, the 'N' key gets pressed (in the terminal the script is running in), then I want to abort the killing and go back to monitoring the screensaver. This will give me an escape route if the screensaver comes on while I'm getting coffee.

Some sort of Bond-style countdown would be nice, too.

Actually even better would be to notice when the screensaver get unlocked, and stop the countdown if so, going back into monitoring mode. Then I don't even have to worry about remembering to press N.


Solution

  • As mob said, threads and select are overcomplicating this a bit. So here's something nice and simple with Term::ReadKey, which lets you do what you asked for in the first place: Wait for a key to be pressed, but timeout if no key is pressed within 15 minutes.

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    use Term::ReadKey;
    my $cmd = "dbus-monitor --session \"type='signal', interface='org.gnome.ScreenSaver',member='ActiveChanged'\"";
    
    open(IN, "$cmd |");
    
    ReadMode 'cbreak';    # return keypress immediately without waiting for "Enter"
    
    while (<IN>) {
      if (m/^\s+boolean true/) {
        print "*** Screensaver is active ***\n";
        print "*** Sleeping before megadeath....\n";
    
        my $key = ReadKey 900;    # timeout after 900 seconds = 15 minutes
        if (defined $key) {
          print "*** A key was pressed; megadeath averted\n";
        } else {
          print "*** killing all jla processes on anvil...\n";
          my $result = `ssh anvil pkill -u jla`;
          print "*** should all be dead\n";
          print $result;
        }
      } elsif (m/^\s+boolean false/) {
        print "*** Screensaver is no longer active ***\n";
      }
    }
    
    ReadMode 'restore';    # back to normal input mode
    

    (Code is syntactically correct, but has not been run, so it is not fully tested. You may want to also set the 'noecho' ReadMode in addition to 'cbreak' to prevent the keypress which disables megadeath from appearing on the screen.)