Here's a refactored version that seems to do what you want. You'll have to merge it into your version. I cut out all the option and config file handling because it was easier for me to ignore all that.
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
use POSIX qw(strftime);
use POE;
use POE::Wheel::FollowTail;
use POE::Component::IRC::State;
use POE::Component::IRC::Plugin::AutoJoin;
sub parse_nick { (split /!/, shift)[0] }
# Simplify testing by removing dependency on external data.
my $server_address = "10.0.0.25";
my $server_port = 6667;
my $channel = "#test";
my $nick = "testnick";
my $username = "testusername";
my $desc = "test description";
# Unfortunately, I don't have a "messages" log.
my %FOLLOWS = (SYSTEM => '/var/log/system.log');
my $SKIPPING = 0;
my $CHANNEL = $channel;
POE::Session->create(
package_states => [
main => [
qw(
_default
_start irc_public irc_join
my_tailed my_heartbeat
)
],
],
);
POE::Kernel->run();
exit;
sub _start {
my $irc = POE::Component::IRC::State->spawn(
nick => $nick,
Username => $username,
ircname => $desc,
server => $server_address,
);
# Save the object to avoid immediate destruction.
$_[HEAP]{irc} = $irc;
$irc->plugin_add(
'AutoJoin',
POE::Component::IRC::Plugin::AutoJoin->new(
Channels => {$CHANNEL => ''},
),
);
$irc->yield(register => 'all');
$irc->yield('connect');
# Start heartbeat in this session, not in $irc.
$_[KERNEL]->yield("my_heartbeat");
# Start following logs.
# We don't need separate sessions for this.
while (my ($keyword, $file_name) = each %FOLLOWS) {
my $wheel = POE::Wheel::FollowTail->new(
Filename => $file_name,
InputEvent => 'my_tailed',
);
$_[HEAP]->{tails}{$wheel->ID} = {
wheel => $wheel,
keyword => $keyword,
file_name => $file_name,
};
}
return;
}
# Dump logged lines to IRC.
# Sidestep server and PoCo::IRC flood protections.
sub my_tailed {
my ($line, $wheel_id) = @_[ARG0 .. ARG1];
## PoCo::IRC has throttling built in, but no external visibility
## so this is reaching "under the hood"
my $irc = $_[HEAP]{irc};
my $send_queue = $irc->{send_queue};
my $keyword = $_[HEAP]{tails}{$wheel_id}{keyword};
## handle "no need to keep skipping" transition
if ($SKIPPING and @$send_queue < 1) {
$irc->yield(privmsg => $CHANNEL => "[discarded $SKIPPING messa
+ges]");
$SKIPPING = 0;
}
## handle potential message display
if ($SKIPPING or @$send_queue > 3) { # 3 msgs per 10 seconds
$SKIPPING++;
$_[KERNEL]->delay($_[STATE] => 0.5);
return;
}
my $timestamp = strftime("%T", localtime());
$irc->yield(privmsg => $CHANNEL => "$timestamp: $keyword $line");
}
# Periodically announce that we're still alive.
# Part of the original exercise.
sub my_heartbeat {
foreach my $wheel_id (keys %{$_[HEAP]{tails}}) {
$_[KERNEL]->yield("my_tailed", "heartbeat", $wheel_id);
}
$_[KERNEL]->delay($_[STATE] => 10);
}
# Default event handler catches and displays all unexpected events.
# Very handy for debugging.
sub _default {
my ($event, $args) = @_[ARG0 .. $#_];
my @output = ("$event: ");
for my $arg (@$args) {
if (ref $arg eq 'ARRAY') {
push @output, '[' . join ', ', @$arg . ']';
}
else {
push @output, "'$arg'";
}
}
print join ' ', @output, "\n";
return;
}
# Event when a public message is broadcast to a channel
sub irc_public {
my ($sender, $where, $what) = @_[SENDER, ARG1, ARG2];
my $nick = parse_nick $_[ARG0];
my $irc = $_[SENDER]->get_heap;
# Does nothing for now.
}
# Announce when we've synchronized with the channel.
sub irc_join {
my $nick = parse_nick $_[ARG0];
my $channel = $_[ARG1];
my $irc = $_[SENDER]->get_heap;
if ($nick eq $irc->nick_name) {
$irc->yield(privmsg => $channel, "I am online and responding t
+o commands");
}
}