mirror of https://github.com/pragma-/pbot.git
Refactor SelectHandler to use PBot::IRC's select loop
This commit is contained in:
parent
8b093d313c
commit
06d986e11e
17
PBot/PBot.pm
17
PBot/PBot.pm
|
@ -100,7 +100,7 @@ sub initialize {
|
||||||
my ($item, $value) = split /=/, $arg, 2;
|
my ($item, $value) = split /=/, $arg, 2;
|
||||||
|
|
||||||
if (not defined $item or not defined $value) {
|
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;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,8 +174,11 @@ sub initialize {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# prepare the IRC engine
|
||||||
|
$self->{irc} = PBot::IRC->new;
|
||||||
|
|
||||||
# prepare remaining core PBot modules -- do not change this order
|
# 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->{event_dispatcher} = PBot::EventDispatcher->new(pbot => $self, %conf);
|
||||||
$self->{users} = PBot::Users->new(pbot => $self, filename => "$conf{data_dir}/users", %conf);
|
$self->{users} = PBot::Users->new(pbot => $self, filename => "$conf{data_dir}/users", %conf);
|
||||||
$self->{antiflood} = PBot::AntiFlood->new(pbot => $self, %conf);
|
$self->{antiflood} = PBot::AntiFlood->new(pbot => $self, %conf);
|
||||||
|
@ -188,7 +191,6 @@ sub initialize {
|
||||||
$self->{functions} = PBot::Functions->new(pbot => $self, %conf);
|
$self->{functions} = PBot::Functions->new(pbot => $self, %conf);
|
||||||
$self->{refresher} = PBot::Refresher->new(pbot => $self);
|
$self->{refresher} = PBot::Refresher->new(pbot => $self);
|
||||||
$self->{ignorelist} = PBot::IgnoreList->new(pbot => $self, filename => "$conf{data_dir}/ignorelist", %conf);
|
$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->{irchandlers} = PBot::IRCHandlers->new(pbot => $self, %conf);
|
||||||
$self->{interpreter} = PBot::Interpreter->new(pbot => $self, %conf);
|
$self->{interpreter} = PBot::Interpreter->new(pbot => $self, %conf);
|
||||||
$self->{lagchecker} = PBot::LagChecker->new(pbot => $self, %conf);
|
$self->{lagchecker} = PBot::LagChecker->new(pbot => $self, %conf);
|
||||||
|
@ -332,16 +334,17 @@ sub exit {
|
||||||
|
|
||||||
# main loop
|
# main loop
|
||||||
sub do_one_loop {
|
sub do_one_loop {
|
||||||
my $self = shift;
|
my ($self) = @_;
|
||||||
$self->{irc}->do_one_loop() if $self->{connected};
|
$self->{irc}->do_one_loop();
|
||||||
$self->{select_handler}->do_select;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# main entry point
|
# main entry point
|
||||||
sub start {
|
sub start {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
$self->connect;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
$self->connect if not $self->{connected};
|
|
||||||
$self->do_one_loop;
|
$self->do_one_loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# File: SelectHandler.pm
|
# 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
|
# 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
|
# 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 PBot::Imports;
|
||||||
|
|
||||||
use IO::Select;
|
|
||||||
|
|
||||||
sub initialize {
|
sub initialize {
|
||||||
my ($self, %conf) = @_;
|
# nothing to initialize
|
||||||
$self->{select} = IO::Select->new();
|
|
||||||
$self->{readers} = {};
|
|
||||||
$self->{buffers} = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub add_reader {
|
sub add_reader {
|
||||||
my ($self, $handle, $subref) = @_;
|
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} = '';
|
$self->{buffers}->{$handle} = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
sub remove_reader {
|
sub remove_reader {
|
||||||
my ($self, $handle) = @_;
|
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};
|
delete $self->{buffers}->{$handle};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub do_select {
|
sub on_select_read {
|
||||||
my ($self) = @_;
|
my ($self, $handle, $subref) = @_;
|
||||||
|
|
||||||
# maximum read length
|
# maximum read length
|
||||||
my $length = 8192;
|
my $length = 8192;
|
||||||
|
|
||||||
# check if any readers can read
|
# read from handle
|
||||||
my @ready = $self->{select}->can_read(.1);
|
my $ret = sysread($handle, my $buf, $length);
|
||||||
|
|
||||||
foreach my $fh (@ready) {
|
# error reading
|
||||||
# read from handle
|
if (not defined $ret) {
|
||||||
my $ret = sysread($fh, my $buf, $length);
|
$self->{pbot}->{logger}->log("SelectHandler: Error reading $handle: $!\n");
|
||||||
|
$self->remove_reader($handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
# error reading
|
# reader closed
|
||||||
if (not defined $ret) {
|
if ($ret == 0) {
|
||||||
$self->{pbot}->{logger}->log("SelectHandler: Error reading $fh: $!\n");
|
# is there anything in reader's buffer?
|
||||||
$self->remove_reader($fh);
|
if (length $self->{buffers}->{$handle}) {
|
||||||
next;
|
# send buffer to reader subref
|
||||||
|
$self->{readers}->{$handle}->($self->{buffers}->{$handle});
|
||||||
}
|
}
|
||||||
|
|
||||||
# reader closed
|
# remove reader
|
||||||
if ($ret == 0) {
|
$self->remove_reader($handle);
|
||||||
# is there anything in reader's buffer?
|
return;
|
||||||
if (length $self->{buffers}->{$fh}) {
|
}
|
||||||
# send buffer to reader subref
|
|
||||||
$self->{readers}->{$fh}->($self->{buffers}->{$fh});
|
|
||||||
}
|
|
||||||
|
|
||||||
# remove reader
|
# accumulate input into reader's buffer
|
||||||
$self->remove_reader($fh);
|
$self->{buffers}->{$handle} .= $buf;
|
||||||
|
|
||||||
# skip to next reader
|
# if we read less than max length bytes then this is probably
|
||||||
next;
|
# 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 ($ret < $length) {
|
||||||
if (not exists $self->{readers}->{$fh}) {
|
# send reader's buffer to reader's consumer subref
|
||||||
$self->{pbot}->{logger}->log("Error: no reader for $fh\n");
|
$subref->($self->{buffers}->{$handle});
|
||||||
|
|
||||||
# skip to next reader
|
# clear out reader's buffer
|
||||||
next;
|
$self->{buffers}->{$handle} = '';
|
||||||
}
|
|
||||||
|
|
||||||
# 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} = '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue