http://qs321.pair.com?node_id=1070183


in reply to [POE::Component::IRC] Updating The IRC Log Watcher bot

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.

The immediate problem is that you called $irc->yield("my_heartbeeat") rather than $_[KERNEL]->yield("my_heartbeat") near the end of _start(). The IRC component doesn't know what you mean, and it discards the message.

#!/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"); } }