mirror of
https://github.com/pragma-/pbot.git
synced 2024-12-23 19:22:40 +01:00
Refactor PBot::Timer into PBot::EventQueue
Make better use of PBot::IRC's select loop Remove use of SIGALRM
This commit is contained in:
parent
dcd07d9a68
commit
1a41f9aebb
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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});
|
||||||
|
@ -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}",
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
|
||||||
|
|
||||||
|
# register `eventqueue` bot command
|
||||||
$self->{pbot}->{commands}->register(sub { $self->cmd_eventqueue(@_) }, 'eventqueue', 1);
|
$self->{pbot}->{commands}->register(sub { $self->cmd_eventqueue(@_) }, 'eventqueue', 1);
|
||||||
$self->{pbot}->{capabilities}->add('admin', 'can-eventqueue', 1);
|
|
||||||
|
|
||||||
$self->{timer_func} = sub { $self->on_tick_handler(@_) };
|
# add `can-eventqueue` capability to admin group
|
||||||
|
$self->{pbot}->{capabilities}->add('admin', 'can-eventqueue', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
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},
|
||||||
|
hostmask => $context->{hostmask},
|
||||||
command => $command,
|
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}};
|
||||||
|
|
||||||
|
my $debug = $self->{pbot}->{registry}->get_value('eventqueue', 'debug') // 0;
|
||||||
|
|
||||||
|
# repeating events to re-enqueue
|
||||||
|
my @enqueue;
|
||||||
|
|
||||||
if (@{$self->{event_queue}}) {
|
|
||||||
my $next_tick = 1;
|
|
||||||
my @enqueue = ();
|
|
||||||
for (my $i = 0; $i < @{$self->{event_queue}}; $i++) {
|
for (my $i = 0; $i < @{$self->{event_queue}}; $i++) {
|
||||||
if ($seconds >= $self->{event_queue}->[$i]->{timeout}) {
|
# 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];
|
my $event = $self->{event_queue}->[$i];
|
||||||
$self->{pbot}->{logger}->log("Processing timer event $i: $event->{id}\n") if $debug > 1;
|
|
||||||
|
$self->{pbot}->{logger}->log("Processing event $i: $event->{id}\n") if $debug > 1;
|
||||||
|
|
||||||
|
# call event's subref, passing event as argument
|
||||||
$event->{subref}->($event);
|
$event->{subref}->($event);
|
||||||
|
|
||||||
|
# remove event from queue
|
||||||
splice @{$self->{event_queue}}, $i--, 1;
|
splice @{$self->{event_queue}}, $i--, 1;
|
||||||
|
|
||||||
|
# add event to re-enqueue queue if repeating
|
||||||
push @enqueue, $event if $event->{repeating};
|
push @enqueue, $event if $event->{repeating};
|
||||||
} else {
|
} else {
|
||||||
|
# no more events ready at this time
|
||||||
if ($debug > 2) {
|
if ($debug > 2) {
|
||||||
$self->{pbot}->{logger}->log("Event not ready yet: $self->{event_queue}->[$i]->{id} (timeout=$self->{event_queue}->[$i]->{timeout})\n");
|
$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;
|
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->waitfor($next_tick);
|
# re-enqueue repeating events
|
||||||
|
|
||||||
foreach my $event (@enqueue) {
|
foreach my $event (@enqueue) {
|
||||||
$self->enqueue_event($event->{subref}, $event->{interval}, $event->{id}, 1);
|
$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});
|
return $self->duration_until_next_event;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# default overridable handler, executed whenever timeout is triggered
|
|
||||||
sub on_tick {
|
|
||||||
my ($self) = @_;
|
|
||||||
$self->{pbot}->{logger}->log("Tick! $self->{name} $self->{timeout} $self->{last} $seconds\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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');
|
||||||
|
23
PBot/PBot.pm
23
PBot/PBot.pm
@ -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
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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}--;
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user