Refactor PBot::Timer into PBot::EventQueue

Make better use of PBot::IRC's select loop
Remove use of SIGALRM
This commit is contained in:
Pragmatic Software 2021-06-21 17:26:24 -07:00
parent dcd07d9a68
commit 1a41f9aebb
24 changed files with 206 additions and 199 deletions

View File

@ -36,7 +36,7 @@ sub initialize {
$self->{'ban-exemptions'} = PBot::DualIndexHashObject->new(name => 'Ban exemptions', filename => $filename, pbot => $self->{pbot}); $self->{'ban-exemptions'} = PBot::DualIndexHashObject->new(name => 'Ban exemptions', filename => $filename, pbot => $self->{pbot});
$self->{'ban-exemptions'}->load; $self->{'ban-exemptions'}->load;
$self->{pbot}->{timer}->register(sub { $self->adjust_offenses }, 60 * 60 * 1, 'AntiFlood Adjust Offenses'); $self->{pbot}->{event_queue}->enqueue(sub { $self->adjust_offenses }, 60 * 60 * 1, 'Adjust anti-flood offenses');
$self->{pbot}->{registry}->add_default('text', 'antiflood', 'enforce', $conf{enforce_antiflood} // 1); $self->{pbot}->{registry}->add_default('text', 'antiflood', 'enforce', $conf{enforce_antiflood} // 1);

View File

@ -59,7 +59,7 @@ sub initialize {
$self->{ban_queue} = {}; $self->{ban_queue} = {};
$self->{unban_queue} = {}; $self->{unban_queue} = {};
$self->{pbot}->{timer}->register(sub { $self->flush_unban_queue }, 30, 'Unban Queue'); $self->{pbot}->{event_queue}->enqueue(sub { $self->flush_unban_queue }, 30, 'Flush unban queue');
} }
sub cmd_banlist { sub cmd_banlist {
@ -203,7 +203,7 @@ sub compare_banlist {
$self->{pbot}->{logger}->log("BanList: Saved ban +b $mask no longer exists in $channel.\n"); $self->{pbot}->{logger}->log("BanList: Saved ban +b $mask no longer exists in $channel.\n");
# TODO option to restore ban # TODO option to restore ban
$self->{banlist}->remove($channel, $mask, undef, 1); $self->{banlist}->remove($channel, $mask, undef, 1);
$self->{pbot}->{timer}->dequeue_event("unban $channel $mask"); $self->{pbot}->{event_queue}->dequeue_event("unban $channel $mask");
} }
} }
@ -248,7 +248,7 @@ sub compare_quietlist {
$self->{pbot}->{logger}->log("BanList: Saved quiet +q $mask no longer exists in $channel.\n"); $self->{pbot}->{logger}->log("BanList: Saved quiet +q $mask no longer exists in $channel.\n");
# TODO option to restore quiet # TODO option to restore quiet
$self->{quietlist}->remove($channel, $mask, undef, 1); $self->{quietlist}->remove($channel, $mask, undef, 1);
$self->{pbot}->{timer}->dequeue_event("unmute $channel $mask"); $self->{pbot}->{event_queue}->dequeue_event("unmute $channel $mask");
} }
} }
@ -294,15 +294,15 @@ sub track_mode {
if ($mode eq "-b") { if ($mode eq "-b") {
$self->{banlist}->remove($channel, $mask); $self->{banlist}->remove($channel, $mask);
$self->{pbot}->{timer}->dequeue_event("unban $channel $mask"); $self->{pbot}->{event_queue}->dequeue_event("unban $channel $mask");
# freenode strips channel forwards from unban result if no ban exists with a channel forward # freenode strips channel forwards from unban result if no ban exists with a channel forward
my $join_flood_channel = $self->{pbot}->{registry}->get_value('antiflood', 'join_flood_channel') // '#stop-join-flood'; my $join_flood_channel = $self->{pbot}->{registry}->get_value('antiflood', 'join_flood_channel') // '#stop-join-flood';
$self->{banlist}->remove($channel, "$mask\$$join_flood_channel"); $self->{banlist}->remove($channel, "$mask\$$join_flood_channel");
$self->{pbot}->{timer}->dequeue_event(lc "unban $channel $mask\$$join_flood_channel"); $self->{pbot}->{event_queue}->dequeue_event(lc "unban $channel $mask\$$join_flood_channel");
} elsif ($mode eq "-$mute_char") { } elsif ($mode eq "-$mute_char") {
$self->{quietlist}->remove($channel, $mask); $self->{quietlist}->remove($channel, $mask);
$self->{pbot}->{timer}->dequeue_event("unmute $channel $mask"); $self->{pbot}->{event_queue}->dequeue_event("unmute $channel $mask");
} }
} }
@ -312,7 +312,7 @@ sub track_mode {
if ($nick eq "ChanServ" or $mask =~ m/##fix_your_connection$/i) { if ($nick eq "ChanServ" or $mask =~ m/##fix_your_connection$/i) {
if ($self->{banlist}->exists($channel, $mask)) { if ($self->{banlist}->exists($channel, $mask)) {
$self->{banlist}->set($channel, $mask, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout')); $self->{banlist}->set($channel, $mask, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
$self->{pbot}->{timer}->update_interval("unban $channel $mask", $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout')); $self->{pbot}->{event_queue}->update_interval("unban $channel $mask", $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
} else { } else {
my $data = { my $data = {
reason => 'Temp ban for banned-by-ChanServ or mask is *!*@*##fix_your_connection', reason => 'Temp ban for banned-by-ChanServ or mask is *!*@*##fix_your_connection',
@ -349,7 +349,7 @@ sub track_mode {
$self->{pbot}->{logger}->log("WEIRD MUTE THING $nick...\n"); $self->{pbot}->{logger}->log("WEIRD MUTE THING $nick...\n");
if ($self->{quietlist}->exists($channel, $mask)) { if ($self->{quietlist}->exists($channel, $mask)) {
$self->{quietlist}->set($channel, $mask, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout')); $self->{quietlist}->set($channel, $mask, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
$self->{pbot}->{timer}->update_interval("unmute $channel $mask", $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout')); $self->{pbot}->{event_queue}->update_interval("unmute $channel $mask", $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
} else { } else {
my $data = { my $data = {
reason => 'Temp mute', reason => 'Temp mute',
@ -557,7 +557,7 @@ sub ban_user_timed {
} }
my $method = $mode eq 'b' ? 'unban' : 'unmute'; my $method = $mode eq 'b' ? 'unban' : 'unmute';
$self->{pbot}->{timer}->dequeue_event("$method $channel $mask"); $self->{pbot}->{event_queue}->dequeue_event("$method $channel $mask");
if ($length > 0) { if ($length > 0) {
$self->enqueue_unban($channel, $mode, $mask, $length); $self->enqueue_unban($channel, $mode, $mask, $length);
@ -704,9 +704,9 @@ sub enqueue_unban {
my $method = $mode eq 'b' ? 'unban' : 'unmute'; my $method = $mode eq 'b' ? 'unban' : 'unmute';
$self->{pbot}->{timer}->enqueue_event( $self->{pbot}->{event_queue}->enqueue_event(
sub { sub {
$self->{pbot}->{timer}->update_interval("$method $channel $hostmask", 60 * 15, 1); # try again in 15 minutes $self->{pbot}->{event_queue}->update_interval("$method $channel $hostmask", 60 * 15, 1); # try again in 15 minutes
return if not $self->{pbot}->{joined_channels}; return if not $self->{pbot}->{joined_channels};
$self->unban_user($channel, $mode, $hostmask); $self->unban_user($channel, $mode, $hostmask);
}, $interval, "$method $channel $hostmask", 1 }, $interval, "$method $channel $hostmask", 1

View File

@ -27,7 +27,8 @@ sub initialize {
$self->{pbot}->{registry}->add_default('text', 'general', 'deop_timeout', 300); $self->{pbot}->{registry}->add_default('text', 'general', 'deop_timeout', 300);
$self->{pbot}->{timer}->register(sub { $self->check_opped_timeouts }, 10, 'Check Opped Timeouts'); # TODO: enqueue OP events as needed instead of naively checking every 10 seconds
$self->{pbot}->{event_queue}->enqueue(sub { $self->check_opped_timeouts }, 10, 'Check opped timeouts');
} }
sub track_mode { sub track_mode {

View File

@ -82,8 +82,8 @@ sub cmd_remove {
# clear banlists # clear banlists
$self->{pbot}->{banlist}->{banlist}->remove($context->{arguments}); $self->{pbot}->{banlist}->{banlist}->remove($context->{arguments});
$self->{pbot}->{banlist}->{quietlist}->remove($context->{arguments}); $self->{pbot}->{banlist}->{quietlist}->remove($context->{arguments});
$self->{pbot}->{timer}->dequeue_event("unban $context->{arguments} .*"); $self->{pbot}->{event_queue}->dequeue_event("unban $context->{arguments} .*");
$self->{pbot}->{timer}->dequeue_event("unmute $context->{arguments} .*"); $self->{pbot}->{event_queue}->dequeue_event("unmute $context->{arguments} .*");
# TODO: ignores, etc? # TODO: ignores, etc?
return $self->{channels}->remove($context->{arguments}); return $self->{channels}->remove($context->{arguments});

View File

@ -125,7 +125,7 @@ sub save {
if ($self->{save_queue_timeout}) { if ($self->{save_queue_timeout}) {
# enqueue the save to prevent save-thrashing # enqueue the save to prevent save-thrashing
$self->{pbot}->{timer}->replace_subref_or_enqueue_event( $self->{pbot}->{enqueue_event}->replace_subref_or_enqueue_event(
$subref, $subref,
$self->{save_queue_timeout}, $self->{save_queue_timeout},
"save $self->{name}", "save $self->{name}",

View File

@ -39,7 +39,7 @@ sub initialize {
$self->{pbot}->{registry}->add_trigger('dualindexsqliteobject', "debug_$self->{name}", sub { $self->sqlite_debug_trigger(@_) }); $self->{pbot}->{registry}->add_trigger('dualindexsqliteobject', "debug_$self->{name}", sub { $self->sqlite_debug_trigger(@_) });
$self->{pbot}->{atexit}->register(sub { $self->end; return; }); $self->{pbot}->{atexit}->register(sub { $self->end; return; });
$self->{pbot}->{timer}->register(sub {$self->trim_cache }, 60, "DualIndexSQLiteObject $self->{name} Timer"); $self->{pbot}->{event_queue}->enqueue(sub {$self->trim_cache }, 60, "Trim $self->{name} cache");
$self->begin; $self->begin;
} }
@ -80,7 +80,7 @@ sub end {
$self->{dbh} = undef; $self->{dbh} = undef;
} }
$self->{pbot}->{timer}->unregister("DualIndexSQLiteObject $self->{name} Timer"); $self->{pbot}->{event_queue}->dequeue("Trim $self->{name} cache");
} }
sub load { sub load {

View File

@ -1,6 +1,8 @@
# File: EventDispatcher.pm # File: EventDispatcher.pm
# #
# Purpose: Registers event handlers and dispatches events to them. # Purpose: Registers event handlers and dispatches events to them.
#
# Note: PBot::EventDispatcher has no relation to PBot::EventQueue.
# 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

View File

@ -1,50 +1,33 @@
# File: Timer.pm # File: EventQueue.pm
# #
# Purpose: Provides functionality to register subroutines/events to be invoked # Purpose: Provides functionality to manage event subroutines which are invoked
# at a future time, optionally recurring. # at a future time, optionally recurring.
# #
# If no subroutines/events are registered/enqueued, the default on_tick() # Note: PBot::EventQueue has no relation to PBot::EventDispatcher.
# method, which can be overridden, is invoked.
#
# Uses own internal seconds counter and relative-intervals to avoid
# timeout desyncs due to system clock changes.
#
# Note: Uses ALARM signal.
# 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
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
package PBot::Timer; package PBot::EventQueue;
use parent 'PBot::Class'; use parent 'PBot::Class';
use PBot::Imports; use PBot::Imports;
use Time::Duration qw/concise duration/; use Time::HiRes qw/time/;
use Time::Duration;
our $seconds //= 0;
our $waitfor //= 1;
our @timer_funcs;
# alarm signal handler (poor-man's timer)
$SIG{ALRM} = sub {
$seconds += $waitfor;
foreach my $func (@timer_funcs) { &$func; }
};
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
my $timeout = $conf{timeout} // 10;
$self->{name} = $conf{name} // "Unnamed ${timeout}s Timer"; # array of pending events
$self->{enabled} = 0;
$self->{event_queue} = []; $self->{event_queue} = [];
$self->{last} = $seconds;
$self->{timeout} = $timeout;
$self->{pbot}->{commands}->register(sub { $self->cmd_eventqueue(@_) }, 'eventqueue', 1); # register `eventqueue` bot command
$self->{pbot}->{commands}->register(sub { $self->cmd_eventqueue(@_) }, 'eventqueue', 1);
# add `can-eventqueue` capability to admin group
$self->{pbot}->{capabilities}->add('admin', 'can-eventqueue', 1); $self->{pbot}->{capabilities}->add('admin', 'can-eventqueue', 1);
$self->{timer_func} = sub { $self->on_tick_handler(@_) };
} }
sub cmd_eventqueue { sub cmd_eventqueue {
@ -63,6 +46,7 @@ sub cmd_eventqueue {
my $result = eval { my $result = eval {
my $text = "Queued events:\n"; my $text = "Queued events:\n";
my ($regex) = $self->{pbot}->{interpreter}->shift_arg($context->{arglist}); my ($regex) = $self->{pbot}->{interpreter}->shift_arg($context->{arglist});
my $i = 0; my $i = 0;
@ -76,19 +60,29 @@ sub cmd_eventqueue {
$events++; $events++;
my $duration = concise duration $event->{timeout} - $seconds; my $duration = $event->{timeout} - time;
$text .= " $i) in $duration: $event->{id}";
if ($duration < 0) {
# current time has passed an event's time but the
# event hasn't left the queue yet. we'll show these
# as, e.g., "pending 5s ago"
$duration = 'pending ' . concise ago -$duration;
} else {
$duration = 'in ' . concise duration $duration;
}
$text .= " $i) $duration: $event->{id}";
$text .= ' [R]' if $event->{repeating}; $text .= ' [R]' if $event->{repeating};
$text .= ";\n"; $text .= ";\n";
} }
return "No events found." if $events == 0; return "No events found." if $events == 0;
return $text; return $text . "$events events.\n";
}; };
if ($@) { if (my $error = $@) {
my $error = $@; # strip source information to prettify error for non-developer consumption
$error =~ s/ at PBot.*//; $error =~ s/ at PBot.*//;
return "Bad regex: $error"; return "Bad regex: $error";
} }
@ -98,22 +92,28 @@ sub cmd_eventqueue {
if ($command eq 'add') { if ($command eq 'add') {
my ($duration, $command) = $self->{pbot}->{interpreter}->split_args($context->{arglist}, 2); my ($duration, $command) = $self->{pbot}->{interpreter}->split_args($context->{arglist}, 2);
return "Usage: eventqueue add <relative time> <command> [-repeat]" if not defined $duration or not defined $command;
my ($delay, $error) = $self->{pbot}->{parsedate}->parsedate($duration); if (not defined $duration or not defined $command) {
return "Usage: eventqueue add <relative time> <command> [-repeat]";
}
# convert text like "5 minutes" or "1 week" or "next tuesday" to seconds
my ($seconds, $error) = $self->{pbot}->{parsedate}->parsedate($duration);
return $error if defined $error; return $error if defined $error;
my $repeating = 0; # check for `-repeating` at front or end of command
$repeating = 1 if $command =~ s/^-repeat\s+|\s+-repeat$//g; my $repeating = $command =~ s/^-repeat\s+|\s+-repeat$//g;
my $cmd = { my $cmd = {
nick => $context->{nick}, nick => $context->{nick},
user => $context->{user}, user => $context->{user},
host => $context->{host}, host => $context->{host},
command => $command, hostmask => $context->{hostmask},
command => $command,
}; };
$self->{pbot}->{interpreter}->add_to_command_queue($context->{from}, $cmd, $delay, $repeating); $self->{pbot}->{interpreter}->add_to_command_queue($context->{from}, $cmd, $seconds, $repeating);
return "Command added to event queue."; return "Command added to event queue.";
} }
@ -127,44 +127,39 @@ sub cmd_eventqueue {
return "Unknown command '$command'. $usage"; return "Unknown command '$command'. $usage";
} }
sub start {
my $self = shift;
$self->{enabled} = 1;
push @timer_funcs, $self->{timer_func};
alarm 1;
}
sub stop {
my $self = shift;
$self->{enabled} = 0;
@timer_funcs = grep { $_ != $self->{timer_func} } @timer_funcs;
}
sub find_enqueue_position { sub find_enqueue_position {
my ($self, $value) = @_; my ($self, $time) = @_;
# no events in queue yet, early-return first position
return 0 if not @{$self->{event_queue}}; return 0 if not @{$self->{event_queue}};
if ($value < $self->{event_queue}->[0]->{timeout}) { # early-return first position if event's time is less
# than first position's
if ($time < $self->{event_queue}->[0]->{timeout}) {
return 0; return 0;
} }
if ($value > $self->{event_queue}->[@{$self->{event_queue}} - 1]->{timeout}) { # early-return last position if event's time is greater
if ($time > $self->{event_queue}->[@{$self->{event_queue}} - 1]->{timeout}) {
return scalar @{$self->{event_queue}}; return scalar @{$self->{event_queue}};
} }
# binary search to find enqueue position
my $lo = 0; my $lo = 0;
my $hi = scalar @{$self->{event_queue}} - 1; my $hi = scalar @{$self->{event_queue}} - 1;
while ($lo <= $hi) { while ($lo <= $hi) {
my $mid = int (($hi + $lo) / 2); my $mid = int (($hi + $lo) / 2);
if ($value < $self->{event_queue}->[$mid]->{timeout}) { if ($time < $self->{event_queue}->[$mid]->{timeout}) {
$hi = $mid - 1; $hi = $mid - 1;
} elsif ($value > $self->{event_queue}->[$mid]->{timeout}) { } elsif ($time > $self->{event_queue}->[$mid]->{timeout}) {
$lo = $mid + 1; $lo = $mid + 1;
} else { } else {
while ($mid < @{$self->{event_queue}} and $self->{event_queue}->[$mid]->{timeout} == $value) { while ($mid < @{$self->{event_queue}} and $self->{event_queue}->[$mid]->{timeout} == $time) {
# found a slot with the same time. we "slide" down the array
# to append this event to the end of this region of same-times.
$mid++; $mid++;
} }
return $mid; return $mid;
@ -175,57 +170,64 @@ sub find_enqueue_position {
} }
sub replace_subref_or_enqueue_event { sub replace_subref_or_enqueue_event {
my ($self, $ref, $interval, $id, $repeating) = @_; my ($self, $subref, $interval, $id, $repeating) = @_;
# find events matching id
my @events = grep { $_->{id} eq $id } @{$self->{event_queue}}; my @events = grep { $_->{id} eq $id } @{$self->{event_queue}};
# no events found, enqueue new event
if (not @events) { if (not @events) {
$self->enqueue_event($ref, $interval, $id, $repeating); $self->enqueue_event($subref, $interval, $id, $repeating);
return; return;
} }
# otherwise update existing events
foreach my $event (@events) { foreach my $event (@events) {
$event->{subref} = $ref; $event->{subref} = $subref;
} }
} }
sub replace_or_enqueue_event { sub replace_or_enqueue_event {
my ($self, $ref, $interval, $id, $repeating) = @_; my ($self, $subref, $interval, $id, $repeating) = @_;
# remove event if it exists
$self->dequeue_event($id) if $self->exists($id); $self->dequeue_event($id) if $self->exists($id);
$self->enqueue_event($ref, $interval, $id, $repeating);
# enqueue new event
$self->enqueue_event($subref, $interval, $id, $repeating);
} }
sub enqueue_event_unless_exists { sub enqueue_event_unless_exists {
my ($self, $ref, $interval, $id, $repeating) = @_; my ($self, $subref, $interval, $id, $repeating) = @_;
# event already exists, bail out
return if $self->exists($id); return if $self->exists($id);
$self->enqueue_event($ref, $interval, $id, $repeating);
# enqueue new event
$self->enqueue_event($subref, $interval, $id, $repeating);
} }
sub enqueue_event { sub enqueue_event {
my ($self, $ref, $interval, $id, $repeating) = @_; my ($self, $subref, $interval, $id, $repeating) = @_;
$id //= 'anonymous event'; $id //= 'an event';
$repeating //= 0; $repeating //= 0;
$interval //= 0; $interval //= 0;
my $event = { my $event = {
id => $id, id => $id,
subref => $ref, subref => $subref,
interval => $interval, interval => $interval,
timeout => $seconds + $interval, timeout => time + $interval,
repeating => $repeating, repeating => $repeating,
}; };
my $i = $self->find_enqueue_position($event->{timeout}); my $i = $self->find_enqueue_position($event->{timeout});
splice @{$self->{event_queue}}, $i, 0, $event; splice @{$self->{event_queue}}, $i, 0, $event;
if ($interval < $waitfor) { my $debug = $self->{pbot}->{registry}->get_value('eventqueue', 'debug') // 0;
$self->waitfor($interval);
}
my $debug = $self->{pbot}->{registry}->get_value('timer', 'debug') // 0;
if ($debug > 1) { if ($debug > 1) {
$self->{pbot}->{logger}->log("Enqueued new timer event $id at position $i: timeout=$event->{timeout} interval=$interval repeating=$repeating\n"); $self->{pbot}->{logger}->log("Enqueued new event $id at position $i: timeout=$event->{timeout} interval=$interval repeating=$repeating\n");
} }
} }
@ -267,12 +269,14 @@ sub execute_and_dequeue_event {
return $self->dequeue_event($id, 1); return $self->dequeue_event($id, 1);
} }
sub register { # adds event with repeating defaulting to enabled
my ($self, $ref, $interval, $id) = @_; sub enqueue {
$self->enqueue_event($ref, $interval, $id, 1); my ($self, $subref, $interval, $id, $repeating) = @_;
$repeating //= 1;
$self->enqueue_event($subref, $interval, $id, $repeating);
} }
sub unregister { sub dequeue {
my ($self, $id) = @_; my ($self, $id) = @_;
$self->dequeue_event($id); $self->dequeue_event($id);
} }
@ -299,8 +303,11 @@ sub update_interval {
for (my $i = 0; $i < @{$self->{event_queue}}; $i++) { for (my $i = 0; $i < @{$self->{event_queue}}; $i++) {
if ($self->{event_queue}->[$i]->{id} eq $id) { if ($self->{event_queue}->[$i]->{id} eq $id) {
if ($dont_enqueue) { if ($dont_enqueue) {
# update interval in-place without moving event to new place in queue
# (allows event to fire at expected time, then updates to new timeout afterwards)
$self->{event_queue}->[$i]->{interval} = $interval; $self->{event_queue}->[$i]->{interval} = $interval;
} else { } else {
# remove and add event in new position in queue
my $event = splice(@{$self->{event_queue}}, $i, 1); my $event = splice(@{$self->{event_queue}}, $i, 1);
$self->enqueue_event($event->{subref}, $interval, $id, $event->{repeating}); $self->enqueue_event($event->{subref}, $interval, $id, $event->{repeating});
} }
@ -309,60 +316,57 @@ sub update_interval {
} }
} }
sub waitfor { sub duration_until_next_event {
my ($self, $duration) = @_; my ($self) = @_;
$duration = 1 if $duration < 1; return 0 if not @{$self->{event_queue}};
alarm $duration; return $self->{event_queue}->[0]->{timeout} - time;
$waitfor = $duration;
} }
sub on_tick_handler { # invokes the next event, if ready, and then returns seconds until next event
sub do_next_event {
my ($self) = @_; my ($self) = @_;
return if not $self->{enabled};
my $debug = $self->{pbot}->{registry}->get_value('timer', 'debug') // 0; # early-return if no events available
$self->{pbot}->{logger}->log("$self->{name} tick $seconds\n") if $debug; return 0 if not @{$self->{event_queue}};
if (@{$self->{event_queue}}) { my $debug = $self->{pbot}->{registry}->get_value('eventqueue', 'debug') // 0;
my $next_tick = 1;
my @enqueue = ();
for (my $i = 0; $i < @{$self->{event_queue}}; $i++) {
if ($seconds >= $self->{event_queue}->[$i]->{timeout}) {
my $event = $self->{event_queue}->[$i];
$self->{pbot}->{logger}->log("Processing timer event $i: $event->{id}\n") if $debug > 1;
$event->{subref}->($event);
splice @{$self->{event_queue}}, $i--, 1;
push @enqueue, $event if $event->{repeating};
} else {
if ($debug > 2) {
$self->{pbot}->{logger}->log("Event not ready yet: $self->{event_queue}->[$i]->{id} (timeout=$self->{event_queue}->[$i]->{timeout})\n");
}
$next_tick = $self->{event_queue}->[$i]->{timeout} - $seconds; # repeating events to re-enqueue
last; my @enqueue;
for (my $i = 0; $i < @{$self->{event_queue}}; $i++) {
# we call time for a fresh time, instead of using a stale $now that
# could be well in the past depending on a previous event's duration
if (time >= $self->{event_queue}->[$i]->{timeout}) {
my $event = $self->{event_queue}->[$i];
$self->{pbot}->{logger}->log("Processing event $i: $event->{id}\n") if $debug > 1;
# call event's subref, passing event as argument
$event->{subref}->($event);
# remove event from queue
splice @{$self->{event_queue}}, $i--, 1;
# add event to re-enqueue queue if repeating
push @enqueue, $event if $event->{repeating};
} else {
# no more events ready at this time
if ($debug > 2) {
$self->{pbot}->{logger}->log("Event not ready yet: $self->{event_queue}->[$i]->{id} (timeout=$self->{event_queue}->[$i]->{timeout})\n");
} }
}
$self->waitfor($next_tick); last;
foreach my $event (@enqueue) {
$self->enqueue_event($event->{subref}, $event->{interval}, $event->{id}, 1);
} }
} else {
# no queued events, call default overridable on_tick() method if timeout has elapsed
if ($seconds - $self->{last} >= $self->{timeout}) {
$self->{last} = $seconds;
$self->on_tick;
}
$self->waitfor($self->{timeout} - $seconds - $self->{last});
} }
}
# default overridable handler, executed whenever timeout is triggered # re-enqueue repeating events
sub on_tick { foreach my $event (@enqueue) {
my ($self) = @_; $self->enqueue_event($event->{subref}, $event->{interval}, $event->{id}, 1);
$self->{pbot}->{logger}->log("Tick! $self->{name} $self->{timeout} $self->{last} $seconds\n"); }
return $self->duration_until_next_event;
} }
1; 1;

View File

@ -64,7 +64,8 @@ sub initialize {
$self->{pbot}->{event_dispatcher}->register_handler('pbot.join', sub { $self->on_self_join(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('pbot.join', sub { $self->on_self_join(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('pbot.part', sub { $self->on_self_part(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('pbot.part', sub { $self->on_self_part(@_) });
$self->{pbot}->{timer}->register(sub { $self->check_pending_whos }, 10, 'Check Pending Whos'); # TODO: enqueue these events as needed instead of naively checking every 10 seconds
$self->{pbot}->{event_queue}->enqueue(sub { $self->check_pending_whos }, 10, 'Check pending WHOs');
} }
sub default_handler { sub default_handler {

View File

@ -98,7 +98,7 @@ sub enqueue_ignores {
my $interval = $timeout - $now; my $interval = $timeout - $now;
$interval = 0 if $interval < 0; $interval = 0 if $interval < 0;
$self->{pbot}->{timer}->enqueue_event(sub { $self->{pbot}->{event_queue}->enqueue_event(sub {
$self->remove($channel, $hostmask); $self->remove($channel, $hostmask);
}, $interval, "ignore_timeout $channel $hostmask" }, $interval, "ignore_timeout $channel $hostmask"
); );
@ -136,9 +136,9 @@ sub add {
$self->{ignorelist}->add($channel, $hostmask, $data); $self->{ignorelist}->add($channel, $hostmask, $data);
if ($length > 0) { if ($length > 0) {
$self->{pbot}->{timer}->dequeue_event("ignore_timeout $channel $hostmask"); $self->{pbot}->{event_queue}->dequeue_event("ignore_timeout $channel $hostmask");
$self->{pbot}->{timer}->enqueue_event(sub { $self->{pbot}->{event_queue}->enqueue_event(sub {
$self->remove($channel, $hostmask); $self->remove($channel, $hostmask);
}, $length, "ignore_timeout $channel $hostmask" }, $length, "ignore_timeout $channel $hostmask"
); );
@ -159,7 +159,7 @@ sub remove {
$channel = '.*' if $channel !~ /^#/; $channel = '.*' if $channel !~ /^#/;
$self->{pbot}->{timer}->dequeue_event("ignore_timeout $channel $hostmask"); $self->{pbot}->{event_queue}->dequeue_event("ignore_timeout $channel $hostmask");
return $self->{ignorelist}->remove($channel, $hostmask); return $self->{ignorelist}->remove($channel, $hostmask);
} }

View File

@ -887,7 +887,7 @@ sub output_result {
sub add_message_to_output_queue { sub add_message_to_output_queue {
my ($self, $channel, $message, $delay) = @_; my ($self, $channel, $message, $delay) = @_;
$self->{pbot}->{timer}->enqueue_event( $self->{pbot}->{event_queue}->enqueue_event(
sub { sub {
my $context = { my $context = {
from => $channel, from => $channel,
@ -909,7 +909,7 @@ sub add_message_to_output_queue {
sub add_to_command_queue { sub add_to_command_queue {
my ($self, $channel, $command, $delay, $repeating) = @_; my ($self, $channel, $command, $delay, $repeating) = @_;
$self->{pbot}->{timer}->enqueue_event( $self->{pbot}->{event_queue}->enqueue_event(
sub { sub {
my $context = { my $context = {
from => $channel, from => $channel,

View File

@ -45,8 +45,8 @@ sub initialize {
# registry trigger for lag_history_interval changes # registry trigger for lag_history_interval changes
$self->{pbot}->{registry}->add_trigger('lagchecker', 'lag_history_interval', sub { $self->trigger_lag_history_interval(@_) }); $self->{pbot}->{registry}->add_trigger('lagchecker', 'lag_history_interval', sub { $self->trigger_lag_history_interval(@_) });
# timer to send PINGs # enqueue repeating event to send PINGs
$self->{pbot}->{timer}->register( $self->{pbot}->{event_queue}->enqueue(
sub { $self->send_ping }, sub { $self->send_ping },
$self->{pbot}->{registry}->get_value('lagchecker', 'lag_history_interval'), $self->{pbot}->{registry}->get_value('lagchecker', 'lag_history_interval'),
'lag check' 'lag check'
@ -62,7 +62,7 @@ sub initialize {
# registry trigger fires when value changes # registry trigger fires when value changes
sub trigger_lag_history_interval { sub trigger_lag_history_interval {
my ($self, $section, $item, $newvalue) = @_; my ($self, $section, $item, $newvalue) = @_;
$self->{pbot}->{timer}->update_interval('lag check', $newvalue); $self->{pbot}->{event_queue}->update_interval('lag check', $newvalue);
} }
# lagcheck bot command # lagcheck bot command

View File

@ -35,7 +35,7 @@ sub initialize {
$self->{pbot}->{registry}->add_trigger('messagehistory', 'sqlite_commit_interval', sub { $self->sqlite_commit_interval_trigger(@_) }); $self->{pbot}->{registry}->add_trigger('messagehistory', 'sqlite_commit_interval', sub { $self->sqlite_commit_interval_trigger(@_) });
$self->{pbot}->{registry}->add_trigger('messagehistory', 'sqlite_debug', sub { $self->sqlite_debug_trigger(@_) }); $self->{pbot}->{registry}->add_trigger('messagehistory', 'sqlite_debug', sub { $self->sqlite_debug_trigger(@_) });
$self->{pbot}->{timer}->register( $self->{pbot}->{event_queue}->enqueue(
sub { $self->commit_message_history }, sub { $self->commit_message_history },
$self->{pbot}->{registry}->get_value('messagehistory', 'sqlite_commit_interval'), $self->{pbot}->{registry}->get_value('messagehistory', 'sqlite_commit_interval'),
'messagehistory commit' 'messagehistory commit'
@ -47,7 +47,7 @@ sub initialize {
sub sqlite_commit_interval_trigger { sub sqlite_commit_interval_trigger {
my ($self, $section, $item, $newvalue) = @_; my ($self, $section, $item, $newvalue) = @_;
$self->{pbot}->{timer}->update_interval('messagehistory commit', $newvalue); $self->{pbot}->{event_queue}->update_interval('messagehistory commit', $newvalue);
} }
sub sqlite_debug_trigger { sub sqlite_debug_trigger {

View File

@ -191,8 +191,8 @@ sub cmd_reload {
}, },
'banlist' => sub { 'banlist' => sub {
$self->{pbot}->{timer}->dequeue_event('unban #.*'); $self->{pbot}->{event_queue}->dequeue_event('unban #.*');
$self->{pbot}->{timer}->dequeue_event('unmute #.*'); $self->{pbot}->{event_queue}->dequeue_event('unmute #.*');
$self->{pbot}->{banlist}->{banlist}->load; $self->{pbot}->{banlist}->{banlist}->load;
$self->{pbot}->{banlist}->{quietlist}->load; $self->{pbot}->{banlist}->{quietlist}->load;
$self->{pbot}->{banlist}->enqueue_timeouts($self->{pbot}->{banlist}->{banlist}, 'b'); $self->{pbot}->{banlist}->enqueue_timeouts($self->{pbot}->{banlist}->{banlist}, 'b');

View File

@ -37,6 +37,7 @@ use PBot::ChanOps;
use PBot::DualIndexHashObject; use PBot::DualIndexHashObject;
use PBot::DualIndexSQLiteObject; use PBot::DualIndexSQLiteObject;
use PBot::EventDispatcher; use PBot::EventDispatcher;
use PBot::EventQueue;
use PBot::Factoids; use PBot::Factoids;
use PBot::Functions; use PBot::Functions;
use PBot::HashObject; use PBot::HashObject;
@ -55,7 +56,6 @@ use PBot::Registry;
use PBot::Refresher; use PBot::Refresher;
use PBot::SelectHandler; use PBot::SelectHandler;
use PBot::StdinReader; use PBot::StdinReader;
use PBot::Timer;
use PBot::Updater; use PBot::Updater;
use PBot::Users; use PBot::Users;
use PBot::Utils::ParseDate; use PBot::Utils::ParseDate;
@ -178,7 +178,7 @@ sub initialize {
$self->{irc} = PBot::IRC->new; $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->{event_queue} = PBot::EventQueue->new(pbot => $self, name => 'PBot event queue', %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);
@ -213,9 +213,9 @@ sub initialize {
# -- this must happen last after all modules have registered their capabilities -- # -- this must happen last after all modules have registered their capabilities --
$self->{capabilities}->rebuild_botowner_capabilities; $self->{capabilities}->rebuild_botowner_capabilities;
# flush all pending save events to disk at exit # fire all pending save events at exit
$self->{atexit}->register(sub { $self->{atexit}->register(sub {
$self->{timer}->execute_and_dequeue_event('save *'); $self->{event_queue}->execute_and_dequeue_event('save .*');
return; return;
} }
); );
@ -267,9 +267,6 @@ sub connect {
$self->{connected} = 1; $self->{connected} = 1;
# start timer once connected
$self->{timer}->start;
# set up handlers for the IRC engine # set up handlers for the IRC engine
$self->{conn}->add_default_handler(sub { $self->{irchandlers}->default_handler(@_) }, 1); $self->{conn}->add_default_handler(sub { $self->{irchandlers}->default_handler(@_) }, 1);
$self->{conn}->add_handler([251, 252, 253, 254, 255, 302], sub { $self->{irchandlers}->on_init(@_) }); $self->{conn}->add_handler([251, 252, 253, 254, 255, 302], sub { $self->{irchandlers}->on_init(@_) });
@ -308,7 +305,6 @@ sub register_signal_handlers {
sub atexit { sub atexit {
my $self = shift; my $self = shift;
$self->{atexit}->execute_all; $self->{atexit}->execute_all;
alarm 0;
if (exists $self->{logger}) { if (exists $self->{logger}) {
$self->{logger}->log("Good-bye.\n"); $self->{logger}->log("Good-bye.\n");
} else { } else {
@ -335,7 +331,16 @@ sub exit {
# main loop # main loop
sub do_one_loop { sub do_one_loop {
my ($self) = @_; my ($self) = @_;
$self->{irc}->do_one_loop();
# do an irc engine loop (select, eventqueues, etc)
$self->{irc}->do_one_loop;
# check for an available PBot event (returns seconds until next event)
my $waitfor = $self->{event_queue}->do_next_event;
# tell irc select loop to sleep for this many seconds
# (or until its own internal eventqueue has an event)
$self->{irc}->timeout($waitfor);
} }
# main entry point # main entry point

View File

@ -243,13 +243,12 @@ sub execute_process {
# remove atexit handlers # remove atexit handlers
$self->{pbot}->{atexit}->unregister_all; $self->{pbot}->{atexit}->unregister_all;
# FIXME: close databases and files too? Or just set everything to check for $self->{pbot}->{child} == 1 or $context->{pid} == 0?
# execute the provided subroutine, results are stored in $context # execute the provided subroutine, results are stored in $context
eval { eval {
local $SIG{ALRM} = sub { die "Process `$context->{commands}->[0]` timed-out" }; local $SIG{ALRM} = sub { die "Process `$context->{commands}->[0]` timed-out" };
alarm $timeout; alarm $timeout;
$subref->($context); $subref->($context);
alarm 0;
}; };
# check for errors # check for errors
@ -265,9 +264,6 @@ sub execute_process {
$context->{result} =~ s/\s+...propagated at .*$//ms; $context->{result} =~ s/\s+...propagated at .*$//ms;
} }
# turn alarm back on for PBot::Timer
alarm 1;
# print $context to pipe # print $context to pipe
my $json = encode_json $context; my $json = encode_json $context;
print $writer "$json\n"; print $writer "$json\n";

View File

@ -82,8 +82,6 @@ sub paste {
$result =~ s/^\s+|\s+$//g; $result =~ s/^\s+|\s+$//g;
alarm 1; # LWP::UserAgent::Paranoid kills alarm
return $result; return $result;
} }

View File

@ -26,7 +26,7 @@ sub initialize {
sub unload { sub unload {
my $self = shift; my $self = shift;
$self->{pbot}->{timer}->dequeue_event('antirepeat .*'); $self->{pbot}->{event_queue}->dequeue_event('antirepeat .*');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.public'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.public');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.caction'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.caction');
} }
@ -112,7 +112,7 @@ sub on_public {
$self->{offenses}->{$account}->{$channel}->{last_offense} = gettimeofday; $self->{offenses}->{$account}->{$channel}->{last_offense} = gettimeofday;
$self->{offenses}->{$account}->{$channel}->{offenses}++; $self->{offenses}->{$account}->{$channel}->{offenses}++;
$self->{pbot}->{timer}->enqueue_event(sub { $self->{pbot}->{event_queue}->enqueue_event(sub {
my ($event) = @_; my ($event) = @_;
$self->{offenses}->{$account}->{$channel}->{offenses}--; $self->{offenses}->{$account}->{$channel}->{offenses}--;

View File

@ -24,7 +24,7 @@ sub initialize {
sub unload { sub unload {
my ($self) = @_; my ($self) = @_;
$self->{pbot}->{event_dispatcher}->remove_handler('irc.public'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.public');
$self->{pbot}->{timer}->dequeue_event('antitwitter .*'); $self->{pbot}->{event_queue}->dequeue_event('antitwitter .*');
} }
sub on_public { sub on_public {
@ -68,7 +68,7 @@ sub on_public {
); );
$self->{pbot}->{chanops}->gain_ops($channel); $self->{pbot}->{chanops}->gain_ops($channel);
$self->{pbot}->{timer}->enqueue_event(sub { $self->{pbot}->{event_queue}->enqueue_event(sub {
my ($event) = @_; my ($event) = @_;
if (--$self->{offenses}->{$channel}->{$nick}->{offenses} <= 0) { if (--$self->{offenses}->{$channel}->{$nick}->{offenses} <= 0) {
delete $self->{offenses}->{$channel}->{$nick}; delete $self->{offenses}->{$channel}->{$nick};

View File

@ -34,7 +34,7 @@ sub initialize {
sub unload { sub unload {
my $self = shift; my $self = shift;
$self->{pbot}->{commands}->unregister('battleship'); $self->{pbot}->{commands}->unregister('battleship');
$self->{pbot}->{timer}->dequeue_event('battleship loop'); $self->{pbot}->{event_queue}->dequeue_event('battleship loop');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.part'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.part');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.quit'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.quit');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.kick'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.kick');
@ -124,7 +124,7 @@ sub cmd_battleship {
$player = {id => -1, name => undef, missedinputs => 0}; $player = {id => -1, name => undef, missedinputs => 0};
push @{$self->{state_data}->{players}}, $player; push @{$self->{state_data}->{players}}, $player;
$self->{pbot}->{timer}->enqueue_event(sub { $self->{pbot}->{event_queue}->enqueue_event(sub {
$self->run_one_state; $self->run_one_state;
}, 1, 'battleship loop', 1 }, 1, 'battleship loop', 1
); );
@ -147,7 +147,7 @@ sub cmd_battleship {
$player = {id => $id, name => $challengee, missedinputs => 0}; $player = {id => $id, name => $challengee, missedinputs => 0};
push @{$self->{state_data}->{players}}, $player; push @{$self->{state_data}->{players}}, $player;
$self->{pbot}->{timer}->enqueue_event(sub { $self->{pbot}->{event_queue}->enqueue_event(sub {
$self->battleship_loop; $self->battleship_loop;
}, 1, 'battleship loop', 1 }, 1, 'battleship loop', 1
); );
@ -965,7 +965,7 @@ sub show_battlefield {
sub nogame { sub nogame {
my ($self, $state) = @_; my ($self, $state) = @_;
$state->{result} = 'nogame'; $state->{result} = 'nogame';
$self->{pbot}->{timer}->update_repeating('battleship loop', 0); $self->{pbot}->{event_queue}->update_repeating('battleship loop', 0);
return $state; return $state;
} }

View File

@ -32,7 +32,7 @@ sub unload {
$self->{pbot}->{event_dispatcher}->remove_handler('irc.part'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.part');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.quit'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.quit');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.kick'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.kick');
$self->{pbot}->{timer}->dequeue_event('connect4 loop'); $self->{pbot}->{event_queue}->dequeue_event('connect4 loop');
} }
sub on_kick { sub on_kick {
@ -156,7 +156,7 @@ sub cmd_connect4 {
$self->{current_state} = 'accept'; $self->{current_state} = 'accept';
$self->{state_data} = {players => [], counter => 0}; $self->{state_data} = {players => [], counter => 0};
$self->{pbot}->{timer}->enqueue_event( $self->{pbot}->{event_queue}->enqueue_event(
sub { sub {
$self->run_one_state; $self->run_one_state;
}, 1, 'connect4 loop', 1 }, 1, 'connect4 loop', 1
@ -185,7 +185,7 @@ sub cmd_connect4 {
$self->{current_state} = 'accept'; $self->{current_state} = 'accept';
$self->{state_data} = {players => [], counter => 0}; $self->{state_data} = {players => [], counter => 0};
$self->{pbot}->{timer}->enqueue_event( $self->{pbot}->{event_queue}->enqueue_event(
sub { sub {
$self->run_one_state; $self->run_one_state;
}, 1, 'connect4 loop', 1 }, 1, 'connect4 loop', 1
@ -693,7 +693,7 @@ sub show_board {
sub nogame { sub nogame {
my ($self, $state) = @_; my ($self, $state) = @_;
$state->{result} = 'nogame'; $state->{result} = 'nogame';
$self->{pbot}->{timer}->update_repeating('connect4 loop', 0); $self->{pbot}->{event_queue}->update_repeating('connect4 loop', 0);
return $state; return $state;
} }

View File

@ -14,12 +14,12 @@ sub initialize {
$self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) });
$self->{queue} = []; $self->{queue} = [];
$self->{notified} = {}; $self->{notified} = {};
$self->{pbot}->{timer}->register(sub { $self->check_queue }, 1, 'RelayUnreg'); $self->{pbot}->{event_queue}->enqueue(sub { $self->check_queue }, 1, 'RelayUnreg');
} }
sub unload { sub unload {
my $self = shift; my $self = shift;
$self->{pbot}->{timer}->unregister('RelayUnreg'); $self->{pbot}->{event_queue}->dequeue('RelayUnreg');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.public'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.public');
} }

View File

@ -25,7 +25,7 @@ sub unload {
my $self = shift; my $self = shift;
$self->dbi_end; $self->dbi_end;
$self->{pbot}->{commands}->unregister('remindme'); $self->{pbot}->{commands}->unregister('remindme');
$self->{pbot}->{timer}->dequeue_event('reminder .*'); $self->{pbot}->{event_queue}->dequeue_event('reminder .*');
} }
sub enqueue_reminders { sub enqueue_reminders {
@ -56,7 +56,7 @@ sub enqueue_reminders {
$timeout = 10 if $timeout < 10; $timeout = 10 if $timeout < 10;
my $repeating = $reminder->{repeat}; my $repeating = $reminder->{repeat};
$self->{pbot}->{timer}->enqueue_event( $self->{pbot}->{event_queue}->enqueue_event(
sub { sub {
my ($event) = @_; my ($event) = @_;
$self->do_reminder($reminder->{id}, $event); $self->do_reminder($reminder->{id}, $event);
@ -126,7 +126,7 @@ sub add_reminder {
return 0; return 0;
} }
$self->{pbot}->{timer}->enqueue_event( $self->{pbot}->{event_queue}->enqueue_event(
sub { sub {
my ($event) = @_; my ($event) = @_;
$self->do_reminder($id, $event); $self->do_reminder($id, $event);
@ -151,7 +151,7 @@ sub delete_reminder {
return 0; return 0;
} }
$self->{pbot}->{timer}->dequeue_event("reminder $id"); $self->{pbot}->{event_queue}->dequeue_event("reminder $id");
return 1; return 1;
} }

View File

@ -67,7 +67,7 @@ sub initialize {
sub unload { sub unload {
my $self = shift; my $self = shift;
$self->{pbot}->{commands}->unregister('spinach'); $self->{pbot}->{commands}->unregister('spinach');
$self->{pbot}->{timer}->dequeue_event('spinach loop'); $self->{pbot}->{event_queue}->dequeue_event('spinach loop');
$self->{stats}->end if $self->{stats_running}; $self->{stats}->end if $self->{stats_running};
$self->{pbot}->{event_dispatcher}->remove_handler('irc.part'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.part');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.quit'); $self->{pbot}->{event_dispatcher}->remove_handler('irc.quit');
@ -336,7 +336,7 @@ sub cmd_spinach {
$self->{state_data} = { players => [], counter => 0 }; $self->{state_data} = { players => [], counter => 0 };
$self->{current_state} = 'getplayers'; $self->{current_state} = 'getplayers';
$self->{pbot}->{timer}->enqueue_event(sub { $self->{pbot}->{event_queue}->enqueue_event(sub {
$self->run_one_state; $self->run_one_state;
}, 1, 'spinach loop', 1 }, 1, 'spinach loop', 1
); );
@ -409,7 +409,7 @@ sub cmd_spinach {
if (not @{$self->{state_data}->{players}}) { if (not @{$self->{state_data}->{players}}) {
$self->{current_state} = 'nogame'; $self->{current_state} = 'nogame';
$self->{pbot}->{timer}->update_repeating('spinach loop', 0); $self->{pbot}->{event_queue}->update_repeating('spinach loop', 0);
return "/msg $self->{channel} $context->{nick} has left the game! All players have left. The game has been stopped."; return "/msg $self->{channel} $context->{nick} has left the game! All players have left. The game has been stopped.";
} else { } else {
return "/msg $self->{channel} $context->{nick} has left the game!"; return "/msg $self->{channel} $context->{nick} has left the game!";
@ -935,7 +935,7 @@ sub run_one_state {
if (not @{$self->{state_data}->{players}}) { if (not @{$self->{state_data}->{players}}) {
$self->send_message($self->{channel}, "All players have left the game!"); $self->send_message($self->{channel}, "All players have left the game!");
$self->{current_state} = 'nogame'; $self->{current_state} = 'nogame';
$self->{pbot}->{timer}->update_repeating('spinach loop', 0); $self->{pbot}->{event_queue}->update_repeating('spinach loop', 0);
} }
} }
@ -945,7 +945,7 @@ sub run_one_state {
if (not defined $self->{current_state}) { if (not defined $self->{current_state}) {
$self->{pbot}->{logger}->log("Spinach state broke.\n"); $self->{pbot}->{logger}->log("Spinach state broke.\n");
$self->{current_state} = 'nogame'; $self->{current_state} = 'nogame';
$self->{pbot}->{timer}->update_repeating('spinach loop', 0); $self->{pbot}->{event_queue}->update_repeating('spinach loop', 0);
return; return;
} }
@ -2152,7 +2152,7 @@ sub nogame {
delete $self->{stats_running}; delete $self->{stats_running};
} }
$state->{result} = 'nogame'; $state->{result} = 'nogame';
$self->{pbot}->{timer}->update_repeating('spinach loop', 0); $self->{pbot}->{event_queue}->update_repeating('spinach loop', 0);
return $state; return $state;
} }
@ -2205,7 +2205,7 @@ sub getplayers {
$self->send_message($self->{channel}, "All players have left the queue. The game has been stopped."); $self->send_message($self->{channel}, "All players have left the queue. The game has been stopped.");
$self->{current_state} = 'nogame'; $self->{current_state} = 'nogame';
$self->{result} = 'nogame'; $self->{result} = 'nogame';
$self->{pbot}->{timer}->update_repeating('spinach loop', 0); $self->{pbot}->{event_queue}->update_repeating('spinach loop', 0);
return $state; return $state;
} }
} }