mirror of
				https://github.com/pragma-/pbot.git
				synced 2025-11-04 00:27:23 +01:00 
			
		
		
		
	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;
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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} = '';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user