From c815ccbc0d74059cca3624326bed8a05cf29c9a1 Mon Sep 17 00:00:00 2001 From: Pragmatic Software Date: Fri, 6 Mar 2020 13:31:22 -0800 Subject: [PATCH] Use event queue for unban/unmute timeouts --- PBot/BanTracker.pm | 14 ++++++- PBot/ChanOps.pm | 95 +++++++++++++++++++++++++++++++-------------- PBot/Channels.pm | 10 ++++- PBot/IRCHandlers.pm | 9 ++++- PBot/PBot.pm | 10 ++--- 5 files changed, 97 insertions(+), 41 deletions(-) diff --git a/PBot/BanTracker.pm b/PBot/BanTracker.pm index 9a793e9f..b722d456 100644 --- a/PBot/BanTracker.pm +++ b/PBot/BanTracker.pm @@ -83,6 +83,7 @@ sub on_banlist_entry { reason => 'Temp ban on *!*@... or *!...@gateway/web' }; $self->{pbot}->{chanops}->{unban_timeout}->add($channel, $target, $data); + $self->{pbot}->{chanops}->enqueue_unban_timeout($channel, $target, $timeout); } } } @@ -204,13 +205,22 @@ sub track_mode { delete $self->{banlist}->{$channel}->{$mode eq "-b" ? "+b" : "+q"}->{$target}; if ($mode eq "-b") { - if ($self->{pbot}->{chanops}->{unban_timeout}->exists($channel, $target)) { $self->{pbot}->{chanops}->{unban_timeout}->remove($channel, $target); } + if ($self->{pbot}->{chanops}->{unban_timeout}->exists($channel, $target)) { + $self->{pbot}->{chanops}->{unban_timeout}->remove($channel, $target); + $self->{pbot}->{timer}->dequeue_event("unban_timeout $channel $target"); + } elsif ($self->{pbot}->{chanops}->{unban_timeout}->exists($channel, "$target\$##stop_join_flood")) { # freenode strips channel forwards from unban result if no ban exists with a channel forward $self->{pbot}->{chanops}->{unban_timeout}->remove($channel, "$target\$##stop_join_flood"); + $self->{pbot}->{timer}->dequeue_event(lc "unban_timeout $channel $target\$##stop_join_flood"); } } elsif ($mode eq "-q") { - if ($self->{pbot}->{chanops}->{unmute_timeout}->exists($channel, $target)) { $self->{pbot}->{chanops}->{unmute_timeout}->remove($channel, $target); } + if ($self->{pbot}->{chanops}->{unmute_timeout}->exists($channel, $target)) { + $self->{pbot}->{chanops}->{unmute_timeout}->remove($channel, $target); + $self->{pbot}->{timer}->dequeue_event("unmute_timeout $channel $target"); + } else { + $self->{pbot}->{logger}->log("No unmute timeout for $channel $target\n"); + } } } else { $self->{pbot}->{logger}->log("BanTracker: Unknown mode '$mode'\n"); diff --git a/PBot/ChanOps.pm b/PBot/ChanOps.pm index a9e32dd6..8188901e 100644 --- a/PBot/ChanOps.pm +++ b/PBot/ChanOps.pm @@ -37,6 +37,8 @@ sub initialize { $self->{unmute_timeout}->load; + $self->enqueue_timeouts; + $self->{ban_queue} = {}; $self->{unban_queue} = {}; @@ -48,8 +50,6 @@ sub initialize { $self->{pbot}->{registry}->add_default('text', 'general', 'deop_timeout', 300); - $self->{pbot}->{timer}->register(sub { $self->check_unban_timeouts }, 10); - $self->{pbot}->{timer}->register(sub { $self->check_unmute_timeouts }, 10); $self->{pbot}->{timer}->register(sub { $self->check_opped_timeouts }, 10, 'Check Opped Timeouts'); $self->{pbot}->{timer}->register(sub { $self->check_unban_queue }, 30, 'Check Unban Queue'); } @@ -210,8 +210,7 @@ sub unban_user { } sub ban_user_timed { - my $self = shift; - my ($owner, $reason, $mask, $channel, $length, $immediately) = @_; + my ($self, $owner, $reason, $mask, $channel, $length, $immediately) = @_; $channel = lc $channel; $mask = lc $mask; @@ -224,8 +223,12 @@ sub ban_user_timed { $data->{owner} = $owner if defined $owner; $data->{reason} = $reason if defined $reason; $self->{unban_timeout}->add($channel, $mask, $data); + $self->enqueue_unban_timeout($channel, $mask, $length); } else { - if ($self->{unban_timeout}->exists($channel, $mask)) { $self->{unban_timeout}->remove($channel, $mask); } + if ($self->{unban_timeout}->exists($channel, $mask)) { + $self->{unban_timeout}->remove($channel, $mask); + $self->{pbot}->{timer}->dequeue_event("unban_timeout $channel $mask"); + } } } @@ -273,12 +276,16 @@ sub mute_user_timed { $self->mute_user($mask, $channel, $immediately); if ($length > 0) { - my $data = {timeout => gettimeofday + $length}; + my $data = { timeout => gettimeofday + $length }; $data->{owner} = $owner if defined $owner; $data->{reason} = $reason if defined $reason; $self->{unmute_timeout}->add($channel, $mask, $data); + $self->enqueue_unmute_timeout($channel, $mask, $length); } else { - if ($self->{unmute_timeout}->exists($channel, $mask)) { $self->{unmute_timeout}->remove($channel, $mask); } + if ($self->{unmute_timeout}->exists($channel, $mask)) { + $self->{unmute_timeout}->remove($channel, $mask); + $self->{pbot}->{timer}->dequeue_event("unmute_timeout $channel $mask"); + } } } @@ -391,8 +398,10 @@ sub check_ban_queue { sub add_to_unban_queue { my ($self, $channel, $mode, $target) = @_; - push @{$self->{unban_queue}->{$channel}->{$mode}}, $target; - $self->{pbot}->{logger}->log("Added -$mode $target for $channel to unban queue.\n"); + if (not grep { $_ eq $target } @{$self->{unban_queue}->{$channel}->{$mode}}) { + push @{$self->{unban_queue}->{$channel}->{$mode}}, $target; + $self->{pbot}->{logger}->log("Added -$mode $target for $channel to unban queue.\n"); + } } sub check_unban_queue { @@ -437,34 +446,62 @@ sub check_unban_queue { } } -sub check_unban_timeouts { - my $self = shift; - return if not $self->{pbot}->{joined_channels}; - my $now = gettimeofday(); - foreach my $channel ($self->{unban_timeout}->get_keys) { - foreach my $mask ($self->{unban_timeout}->get_keys($channel)) { - if ($self->{unban_timeout}->get_data($channel, $mask, 'timeout') < $now) { - $self->{unban_timeout}->set($channel, $mask, 'timeout', $now + 7200); - $self->unban_user($mask, $channel); - } +sub enqueue_unmute_timeout { + my ($self, $channel, $hostmask, $interval) = @_; + + $self->{pbot}->{timer}->enqueue_event( + sub { + return if not $self->{pbot}->{joined_channels}; + $self->{pbot}->{timer}->update_interval("unmute_timeout $channel $hostmask", 60 * 15, 1); # try again in 15 minutes + $self->unmute_user($hostmask, $channel); + }, $interval, "unmute_timeout $channel $hostmask", 1 + ); +} + +sub enqueue_unban_timeout { + my ($self, $channel, $hostmask, $interval) = @_; + + $self->{pbot}->{timer}->enqueue_event( + sub { + return if not $self->{pbot}->{joined_channels}; + $self->{pbot}->{timer}->update_interval("unban_timeout $channel $hostmask", 60 * 15, 1); # try again in 15 minutes + $self->unban_user($hostmask, $channel); + }, $interval, "unban_timeout $channel $hostmask", 1 + ); +} + +sub enqueue_unmute_timeouts { + my ($self) = @_; + my $now = time; + + foreach my $channel ($self->{unmute_timeout}->get_keys) { + foreach my $mask ($self->{unmute_timeout}->get_keys($channel)) { + my $interval = $self->{unmute_timeout}->get_data($channel, $mask, 'timeout') - $now; + $interval = 10 if $interval < 10; + $self->enqueue_unmute_timeout($channel, $mask, $interval); } } } -sub check_unmute_timeouts { - my $self = shift; - return if not $self->{pbot}->{joined_channels}; - my $now = gettimeofday(); - foreach my $channel ($self->{unmute_timeout}->get_keys) { - foreach my $mask ($self->{unmute_timeout}->get_keys($channel)) { - if ($self->{unmute_timeout}->get_data($channel, $mask, 'timeout') < $now) { - $self->{unmute_timeout}->set($channel, $mask, 'timeout', $now + 7200); - $self->unmute_user($mask, $channel); - } +sub enqueue_unban_timeouts { + my ($self) = @_; + my $now = time; + + foreach my $channel ($self->{unban_timeout}->get_keys) { + foreach my $mask ($self->{unban_timeout}->get_keys($channel)) { + my $interval = $self->{unban_timeout}->get_data($channel, $mask, 'timeout') - $now; + $interval = 10 if $interval < 10; + $self->enqueue_unban_timeout($channel, $mask, $interval); } } } +sub enqueue_timeouts { + my ($self) = @_; + $self->enqueue_unmute_timeouts; + $self->enqueue_unban_timeouts; +} + sub check_opped_timeouts { my $self = shift; my $now = gettimeofday(); diff --git a/PBot/Channels.pm b/PBot/Channels.pm index 63074461..d2d00ee6 100644 --- a/PBot/Channels.pm +++ b/PBot/Channels.pm @@ -82,10 +82,16 @@ sub remove { return "Usage: chanrem " if not defined $arguments or not length $arguments; # clear unban timeouts - if ($self->{pbot}->{chanops}->{unban_timeout}->exists($arguments)) { $self->{pbot}->{chanops}->{unban_timeout}->remove($arguments); } + if ($self->{pbot}->{chanops}->{unban_timeout}->exists($arguments)) { + $self->{pbot}->{chanops}->{unban_timeout}->remove($arguments); + $self->{pbot}->{timer}->dequeue_event("unban_timeout $arguments .*"); + } # clear unmute timeouts - if ($self->{pbot}->{chanops}->{unmute_timeout}->exists($arguments)) { $self->{pbot}->{chanops}->{unmute_timeout}->remove($arguments); } + if ($self->{pbot}->{chanops}->{unmute_timeout}->exists($arguments)) { + $self->{pbot}->{chanops}->{unmute_timeout}->remove($arguments); + $self->{pbot}->{timer}->dequeue_event("unmute_timeout $arguments .*"); + } # TODO: ignores, etc? return $self->{channels}->remove($arguments); diff --git a/PBot/IRCHandlers.pm b/PBot/IRCHandlers.pm index 002ace3d..3a081d06 100644 --- a/PBot/IRCHandlers.pm +++ b/PBot/IRCHandlers.pm @@ -269,6 +269,7 @@ sub on_mode { if ($self->{pbot}->{chanops}->can_gain_ops($channel)) { if ($self->{pbot}->{chanops}->{unban_timeout}->exists($channel, $target)) { $self->{pbot}->{chanops}->{unban_timeout}->set($channel, $target, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout')); + $self->{pbot}->{timer}->update_interval("unban_timeout $channel $target", $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout')); } else { my $data = { reason => 'Temp ban for banned-by-ChanServ or mask is *!*@*##fix_your_connection', @@ -276,6 +277,7 @@ sub on_mode { timeout => gettimeofday + $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout'), }; $self->{pbot}->{chanops}->{unban_timeout}->add($channel, $target, $data); + $self->{pbot}->{chanops}->enqueue_unban_timeout($channel, $target, $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout')); } } } elsif ($target =~ m/^\*!\*@/ or $target =~ m/^\*!.*\@gateway\/web/i) { @@ -294,6 +296,7 @@ sub on_mode { owner => $self->{pbot}->{registry}->get_value('irc', 'botnick'), }; $self->{pbot}->{chanops}->{unban_timeout}->add($channel, $target, $data); + $self->{pbot}->{chanops}->enqueue_unban_timeout($channel, $target, $timeout); } } } @@ -302,6 +305,7 @@ sub on_mode { if ($self->{pbot}->{chanops}->can_gain_ops($channel)) { if ($self->{pbot}->{chanops}->{unmute_timeout}->exists($channel, $target)) { $self->{pbot}->{chanops}->{unmute_timeout}->set($channel, $target, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout')); + $self->{pbot}->{timer}->update_interval("unmute_timeout $channel $target", $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout')); } else { my $data = { reason => 'Temp mute', @@ -309,6 +313,7 @@ sub on_mode { timeout => gettimeofday + $self->{pbot}->{registry}->get_value('bantracker', 'mute_timeout'), }; $self->{pbot}->{chanops}->{unmute_timeout}->add($channel, $target, $data); + $self->{pbot}->{chanops}->enqueue_unmute_timeout($channel, $target, $self->{pbot}->{registry}->get_value('bantracker', 'mute_timeout')); } } } @@ -587,7 +592,7 @@ my $who_pending = 0; sub on_whoreply { my ($self, $event_type, $event) = @_; - my ($ignored, $id, $user, $host, $server, $nick, $usermodes, $gecos) = @{$event->{event}->{args}}; + my (undef, $id, $user, $host, $server, $nick, $usermodes, $gecos) = @{$event->{event}->{args}}; ($nick, $user, $host) = $self->{pbot}->{irchandlers}->normalize_hostmask($nick, $user, $host); my $hostmask = "$nick!$user\@$host"; my $channel; @@ -631,7 +636,7 @@ sub on_whoreply { sub on_whospcrpl { my ($self, $event_type, $event) = @_; - my ($ignored, $id, $user, $host, $nick, $nickserv, $gecos) = @{$event->{event}->{args}}; + my (undef, $id, $user, $host, $nick, $nickserv, $gecos) = @{$event->{event}->{args}}; ($nick, $user, $host) = $self->{pbot}->{irchandlers}->normalize_hostmask($nick, $user, $host); $last_who_id = $id; my $hostmask = "$nick!$user\@$host"; diff --git a/PBot/PBot.pm b/PBot/PBot.pm index 5c12b2ab..68e398b4 100644 --- a/PBot/PBot.pm +++ b/PBot/PBot.pm @@ -435,13 +435,11 @@ sub reload { }, 'blacklist' => sub { - $self->{blacklist}->clear_blacklist; $self->{blacklist}->load_blacklist; return "Blacklist reloaded."; }, 'ban-exemptions' => sub { - $self->{antiflood}->{'ban-exemptions'}->clear; $self->{antiflood}->{'ban-exemptions'}->load; return "Ban exemptions reloaded."; }, @@ -462,25 +460,25 @@ sub reload { }, 'bantimeouts' => sub { - $self->{chanops}->{unban_timeout}->clear; + $self->{timer}->dequeue_event('unban_timeout .*'); $self->{chanops}->{unban_timeout}->load; + $self->{chanops}->enqueue_unban_timeouts; return "Ban timeouts reloaded."; }, 'mutetimeouts' => sub { - $self->{chanops}->{unmute_timeout}->clear; + $self->{timer}->dequeue_event('unmute_timeout .*'); $self->{chanops}->{unmute_timeout}->load; + $self->{chanops}->enqueue_unmute_timeouts; return "Mute timeouts reloaded."; }, 'registry' => sub { - $self->{registry}->{registry}->clear; $self->{registry}->load; return "Registry reloaded."; }, 'factoids' => sub { - $self->{factoids}->{factoids}->clear; $self->{factoids}->load_factoids; return "Factoids reloaded."; }