mirror of
				https://github.com/pragma-/pbot.git
				synced 2025-11-04 08:37:24 +01:00 
			
		
		
		
	Add SelectHandler class to register callbacks for selecting and reading handles; updating StdinReader to use SelectHandler
This commit is contained in:
		
							parent
							
								
									1831d0775d
								
							
						
					
					
						commit
						4a110848e9
					
				
							
								
								
									
										32
									
								
								PBot/PBot.pm
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								PBot/PBot.pm
									
									
									
									
									
								
							@ -21,6 +21,7 @@ STDOUT->autoflush(1);
 | 
			
		||||
use Carp ();
 | 
			
		||||
use PBot::Logger;
 | 
			
		||||
 | 
			
		||||
use PBot::SelectHandler;
 | 
			
		||||
use PBot::StdinReader;
 | 
			
		||||
 | 
			
		||||
use PBot::IRC;
 | 
			
		||||
@ -106,8 +107,10 @@ sub initialize {
 | 
			
		||||
  $self->{commands}           = PBot::Commands->new(pbot => $self);
 | 
			
		||||
  $self->{timer}              = PBot::Timer->new(timeout => 10);
 | 
			
		||||
 | 
			
		||||
  $self->{admins}             = PBot::BotAdmins->new(pbot => $self, filename => $admins_file);
 | 
			
		||||
  $self->{select_handler}     = PBot::SelectHandler->new(pbot => $self);
 | 
			
		||||
  $self->{stdin_reader}       = PBot::StdinReader->new(pbot => $self);
 | 
			
		||||
 | 
			
		||||
  $self->{admins}             = PBot::BotAdmins->new(pbot => $self, filename => $admins_file);
 | 
			
		||||
  $self->admins->load_admins();
 | 
			
		||||
  $self->admins->add_admin($self->{botnick}, '.*', "$self->{botnick}!stdin\@localhost", 60, 'admin');
 | 
			
		||||
  $self->admins->login($self->{botnick}, "$self->{botnick}!stdin\@localhost", 'admin');
 | 
			
		||||
@ -215,8 +218,8 @@ sub do_one_loop {
 | 
			
		||||
  # process IRC events
 | 
			
		||||
  $self->irc->do_one_loop();
 | 
			
		||||
 | 
			
		||||
  # process STDIN events
 | 
			
		||||
  $self->check_stdin();
 | 
			
		||||
  # process SelectHandler
 | 
			
		||||
  $self->{select_handler}->do_select();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub start {
 | 
			
		||||
@ -231,29 +234,6 @@ sub start {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub check_stdin {
 | 
			
		||||
  my $self = shift;
 | 
			
		||||
 | 
			
		||||
  my $input = PBot::StdinReader::check_stdin();
 | 
			
		||||
 | 
			
		||||
  return if not defined $input;
 | 
			
		||||
 | 
			
		||||
  $self->logger->log("---------------------------------------------\n");
 | 
			
		||||
  $self->logger->log("Read '$input' from STDIN\n");
 | 
			
		||||
 | 
			
		||||
  my ($from, $text);
 | 
			
		||||
 | 
			
		||||
  if($input =~ m/^~([^ ]+)\s+(.*)/) {
 | 
			
		||||
    $from = $1;
 | 
			
		||||
    $text = "$self->{trigger}$2";
 | 
			
		||||
  } else {
 | 
			
		||||
    $from = "$self->{botnick}!stdin\@localhost";
 | 
			
		||||
    $text = "$self->{trigger}$input";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return $self->interpreter->process_line($from, $self->{botnick}, "stdin", "localhost", $text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-----------------------------------------------------------------------------------
 | 
			
		||||
# Getters/Setters
 | 
			
		||||
#-----------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										69
									
								
								PBot/SelectHandler.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								PBot/SelectHandler.pm
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
			
		||||
package PBot::SelectHandler;
 | 
			
		||||
 | 
			
		||||
use warnings;
 | 
			
		||||
use strict;
 | 
			
		||||
 | 
			
		||||
use vars qw($VERSION);
 | 
			
		||||
$VERSION = '1.0.0';
 | 
			
		||||
 | 
			
		||||
use IO::Select;
 | 
			
		||||
use Carp ();
 | 
			
		||||
 | 
			
		||||
sub new {
 | 
			
		||||
  if(ref($_[1]) eq 'HASH') {
 | 
			
		||||
    Carp::croak("Options to SelectHandler should be key/value pairs, not hash reference");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  my ($class, %conf) = @_;
 | 
			
		||||
 | 
			
		||||
  my $self = bless {}, $class;
 | 
			
		||||
  $self->initialize(%conf);
 | 
			
		||||
  return $self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub initialize {
 | 
			
		||||
  my ($self, %conf) = @_;
 | 
			
		||||
 | 
			
		||||
  $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference in SelectHandler");
 | 
			
		||||
  $self->{select} = IO::Select->new();
 | 
			
		||||
  $self->{readers} = {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub add_reader {
 | 
			
		||||
  my ($self, $handle, $sub) = @_;
 | 
			
		||||
  $self->{select}->add($handle);
 | 
			
		||||
  $self->{readers}->{$handle} = $sub;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub do_select {
 | 
			
		||||
  my ($self) = @_;
 | 
			
		||||
  my @ready = $self->{select}->can_read(.5);
 | 
			
		||||
  foreach my $fh (@ready) {
 | 
			
		||||
    my $ret = sysread($fh, my $buf, 4096);
 | 
			
		||||
 | 
			
		||||
    if(not defined $ret) {
 | 
			
		||||
      $self->{pbot}->logger->log("Error with $fh: $!\n");
 | 
			
		||||
      $self->{select}->remove($fh);
 | 
			
		||||
      delete $self->{readers}->{$fh};
 | 
			
		||||
      next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if($ret == 0) {
 | 
			
		||||
      $self->{pbot}->logger->log("done with $fh\n");
 | 
			
		||||
      $self->{select}->remove($fh);
 | 
			
		||||
      delete $self->{readers}->{$fh};
 | 
			
		||||
      next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    chomp $buf;
 | 
			
		||||
    $self->{pbot}->logger->log("read from $fh: [$buf]\n");
 | 
			
		||||
 | 
			
		||||
    if(not exists $self->{readers}->{$fh}) {
 | 
			
		||||
      $self->{pbot}->logger->log("Error: no reader for $fh\n");
 | 
			
		||||
    } else {
 | 
			
		||||
      $self->{readers}->{$fh}->($buf);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
@ -4,31 +4,56 @@ use warnings;
 | 
			
		||||
use strict;
 | 
			
		||||
 | 
			
		||||
use vars qw($VERSION);
 | 
			
		||||
 | 
			
		||||
$VERSION = '1.0.0';
 | 
			
		||||
 | 
			
		||||
use IO::Select;
 | 
			
		||||
use POSIX qw(tcgetpgrp getpgrp);  # to check whether process is in background or foreground
 | 
			
		||||
use Carp ();
 | 
			
		||||
 | 
			
		||||
# used to listen for STDIN in non-blocking mode
 | 
			
		||||
my $stdin = IO::Select->new();
 | 
			
		||||
$stdin->add(\*STDIN);
 | 
			
		||||
 | 
			
		||||
# used to check whether process is in background or foreground, for stdin reading
 | 
			
		||||
open TTY, "</dev/tty" or die $!;
 | 
			
		||||
my $tty_fd = fileno(TTY);
 | 
			
		||||
my $foreground = (tcgetpgrp($tty_fd) == getpgrp()) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
sub check_stdin {
 | 
			
		||||
  # make sure we're in the foreground first
 | 
			
		||||
  $foreground = (tcgetpgrp($tty_fd) == getpgrp()) ? 1 : 0;
 | 
			
		||||
  return if not $foreground;
 | 
			
		||||
  
 | 
			
		||||
  if ($stdin->can_read(.5)) {
 | 
			
		||||
    sysread(STDIN, my $input, 1024);
 | 
			
		||||
    chomp $input;
 | 
			
		||||
    return $input;
 | 
			
		||||
sub new {
 | 
			
		||||
  if(ref($_[1]) eq 'HASH') {
 | 
			
		||||
    Carp::croak("Options to StdinReader should be key/value pairs, not hash reference");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  my ($class, %conf) = @_;
 | 
			
		||||
  my $self = bless {}, $class;
 | 
			
		||||
  $self->initialize(%conf);
 | 
			
		||||
  return $self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub initialize {
 | 
			
		||||
  my ($self, %conf) = @_;
 | 
			
		||||
 | 
			
		||||
  $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference in StdinReader");
 | 
			
		||||
 | 
			
		||||
  # used to check whether process is in background or foreground, for stdin reading
 | 
			
		||||
  open TTY, "</dev/tty" or die $!;
 | 
			
		||||
  $self->{tty_fd} = fileno(TTY);
 | 
			
		||||
  $self->{foreground} = (tcgetpgrp($self->{tty_fd}) == getpgrp()) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
  $self->{pbot}->{select_handler}->add_reader(\*STDIN, sub { $self->stdin_reader(@_) });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub stdin_reader {
 | 
			
		||||
  my ($self, $input) = @_;
 | 
			
		||||
 | 
			
		||||
  # make sure we're in the foreground first
 | 
			
		||||
  $self->{foreground} = (tcgetpgrp($self->{tty_fd}) == getpgrp()) ? 1 : 0;
 | 
			
		||||
  return if not $self->{foreground};
 | 
			
		||||
 | 
			
		||||
  $self->{pbot}->logger->log("---------------------------------------------\n");
 | 
			
		||||
  $self->{pbot}->logger->log("Read '$input' from STDIN\n");
 | 
			
		||||
 | 
			
		||||
  my ($from, $text);
 | 
			
		||||
 | 
			
		||||
  if($input =~ m/^~([^ ]+)\s+(.*)/) {
 | 
			
		||||
    $from = $1;
 | 
			
		||||
    $text = "$self->{pbot}->{trigger}$2";
 | 
			
		||||
  } else {
 | 
			
		||||
    $from = "$self->{pbot}->{botnick}!stdin\@localhost";
 | 
			
		||||
    $text = "$self->{pbot}->{trigger}$input";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return $self->{pbot}->interpreter->process_line($from, $self->{pbot}->{botnick}, "stdin", "localhost", $text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ use warnings;
 | 
			
		||||
# These are set automatically by the build/commit script
 | 
			
		||||
use constant {
 | 
			
		||||
  BUILD_NAME     => "PBot",
 | 
			
		||||
  BUILD_REVISION => 523,
 | 
			
		||||
  BUILD_REVISION => 524,
 | 
			
		||||
  BUILD_DATE     => "2014-03-13",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user