diff --git a/PBot/PBot.pm b/PBot/PBot.pm index c5dd0a70..8c50d25c 100644 --- a/PBot/PBot.pm +++ b/PBot/PBot.pm @@ -100,7 +100,7 @@ sub initialize { my ($item, $value) = split /=/, $arg, 2; if (not defined $item or not defined $value) { - print STDERR "Fatal error: unknown argument `$arg`; arguments must be in the form of `section.key=value` (e.g.: irc.botnick=newnick)\n"; + print STDERR "Fatal error: unknown argument `$arg`; arguments must be in the form of `section.key=value` or `path_dir=value` (e.g.: irc.botnick=newnick or data_dir=path)\n"; exit; } @@ -174,8 +174,11 @@ sub initialize { exit; } + # prepare the IRC engine + $self->{irc} = PBot::IRC->new; + # prepare remaining core PBot modules -- do not change this order - $self->{timer} = PBot::Timer->new(pbot => $self, timeout => 10, name => 'PBot Timer', %conf); + $self->{timer} = PBot::Timer->new(pbot => $self, timeout => 10, name => 'PBot Timer', %conf); $self->{event_dispatcher} = PBot::EventDispatcher->new(pbot => $self, %conf); $self->{users} = PBot::Users->new(pbot => $self, filename => "$conf{data_dir}/users", %conf); $self->{antiflood} = PBot::AntiFlood->new(pbot => $self, %conf); @@ -188,7 +191,6 @@ sub initialize { $self->{functions} = PBot::Functions->new(pbot => $self, %conf); $self->{refresher} = PBot::Refresher->new(pbot => $self); $self->{ignorelist} = PBot::IgnoreList->new(pbot => $self, filename => "$conf{data_dir}/ignorelist", %conf); - $self->{irc} = PBot::IRC->new(); $self->{irchandlers} = PBot::IRCHandlers->new(pbot => $self, %conf); $self->{interpreter} = PBot::Interpreter->new(pbot => $self, %conf); $self->{lagchecker} = PBot::LagChecker->new(pbot => $self, %conf); @@ -332,16 +334,17 @@ sub exit { # main loop sub do_one_loop { - my $self = shift; - $self->{irc}->do_one_loop() if $self->{connected}; - $self->{select_handler}->do_select; + my ($self) = @_; + $self->{irc}->do_one_loop(); } # main entry point sub start { my $self = shift; + + $self->connect; + while (1) { - $self->connect if not $self->{connected}; $self->do_one_loop; } } diff --git a/PBot/SelectHandler.pm b/PBot/SelectHandler.pm index 59bd5867..6f6f29a0 100644 --- a/PBot/SelectHandler.pm +++ b/PBot/SelectHandler.pm @@ -1,6 +1,7 @@ # File: SelectHandler.pm # -# Purpose: Invokes select() system call and handles its events. +# Purpose: Adds/removes file handles to/from PBot::IRC's select loop +# and contains handlers for select events. # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this @@ -11,87 +12,75 @@ use parent 'PBot::Class'; use PBot::Imports; -use IO::Select; - sub initialize { - my ($self, %conf) = @_; - $self->{select} = IO::Select->new(); - $self->{readers} = {}; - $self->{buffers} = {}; + # nothing to initialize } sub add_reader { my ($self, $handle, $subref) = @_; - $self->{select}->add($handle); - $self->{readers}->{$handle} = $subref; + + # add file handle to PBot::IRC's select loop + $self->{pbot}->{irc}->addfh($handle, sub { $self->on_select_read($handle, $subref) }, 'r'); + + # create read buffer for this handle $self->{buffers}->{$handle} = ''; } sub remove_reader { my ($self, $handle) = @_; - $self->{select}->remove($handle); - delete $self->{readers}->{$handle}; + + # remove file handle from PBot::IRC's select loop + $self->{pbot}->{irc}->removefh($handle); + + # delete this handle's read buffer delete $self->{buffers}->{$handle}; } -sub do_select { - my ($self) = @_; +sub on_select_read { + my ($self, $handle, $subref) = @_; # maximum read length my $length = 8192; - # check if any readers can read - my @ready = $self->{select}->can_read(.1); + # read from handle + my $ret = sysread($handle, my $buf, $length); - foreach my $fh (@ready) { - # read from handle - my $ret = sysread($fh, my $buf, $length); + # error reading + if (not defined $ret) { + $self->{pbot}->{logger}->log("SelectHandler: Error reading $handle: $!\n"); + $self->remove_reader($handle); + return; + } - # error reading - if (not defined $ret) { - $self->{pbot}->{logger}->log("SelectHandler: Error reading $fh: $!\n"); - $self->remove_reader($fh); - next; + # reader closed + if ($ret == 0) { + # is there anything in reader's buffer? + if (length $self->{buffers}->{$handle}) { + # send buffer to reader subref + $self->{readers}->{$handle}->($self->{buffers}->{$handle}); } - # reader closed - if ($ret == 0) { - # is there anything in reader's buffer? - if (length $self->{buffers}->{$fh}) { - # send buffer to reader subref - $self->{readers}->{$fh}->($self->{buffers}->{$fh}); - } + # remove reader + $self->remove_reader($handle); + return; + } - # remove reader - $self->remove_reader($fh); + # accumulate input into reader's buffer + $self->{buffers}->{$handle} .= $buf; - # skip to next reader - next; - } + # if we read less than max length bytes then this is probably + # a complete message so send it to reader now, otherwise we'll + # continue to accumulate input into reader's buffer and then send + # the buffer when reader closes. + # + # FIXME: this should be line-based or some protocol. - # sanity check for missing reader - if (not exists $self->{readers}->{$fh}) { - $self->{pbot}->{logger}->log("Error: no reader for $fh\n"); + if ($ret < $length) { + # send reader's buffer to reader's consumer subref + $subref->($self->{buffers}->{$handle}); - # skip to next reader - next; - } - - # accumulate input into reader's buffer - $self->{buffers}->{$fh} .= $buf; - - # if we read less than max length bytes then this is probably - # a complete message so send it to reader now, otherwise we'll - # continue to accumulate input into reader's buffer and then send - # the buffer when reader closes. - - if ($ret < $length) { - # send reader's buffer to reader subref - $self->{readers}->{$fh}->($self->{buffers}->{$fh}); - - # clear out reader's buffer - $self->{buffers}->{$fh} = ''; - } + # clear out reader's buffer + $self->{buffers}->{$handle} = ''; } }