Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
package POE::Component::IRC::Tracking; =head1 NAME POE::Component::IRC::Tracking =head1 SYNOPSIS use POE qw( Component::IRC::Tracking ); POE::Component::IRC::Tracking->new("alias"); ...See perldoc POE::Component::IRC... my $botheap = POE::Kernel->alias_resolve("alias")->get_heap; # $botheap->{connected} is true if the bot's connected. my $connected = $botheap->{connected}; # $botheap->{nick} is the current nickname of the bot. my $nick = $botheap->{nick}; # $botheap->{channels} is a hashref whose keys are the channels # the bot is on. my @channels = $connected ? keys %{ $botheap->{channels} } : (); =head1 DEPENDENCY POE::Component::IRC::Tracking isa subclass of POE::Component::IRC. =head1 DESCRIPTION POE::Component::IRC::Tracking adds tracking support to POE::Component: +:IRC, i.e. the bot knows its current nick and the channels it joined. Use it exactly like POE::Component::IRC. =head1 AUTHOR Ingo Blechschmidt, L<>. =head1 LICENSE This package is free software; you can redistribute it and/or modify i +t under the same terms as Perl itself, i.e., under the terms of the GNU Genera +l Public License of the Artistic License. =cut use warnings; use strict; use POE; use base "POE::Component::IRC"; # We've to keep track of the traffic we got. That's necessary for auto +ping and # livecheck. Additionally, we update our nick. sub _parseline { my $line = $_[ARG0]; # Hackery. # # :thestars.gnus 001 nick :Welcome to the Internet Relay Network nic +k!~a@thestars.gnus # :thestars.gnus 376 nick :End of MOTD command. # # Why do we do this? "You *are* already recording the nick! [see C<c +onnect> # and C<irc_433> subs]" But: If the nick we NICKed to is too long fo +r the # server, it's silently cut off. We can't know that. So, we update o +ur # information from the server, which is guaranteed to be correct. if($line =~ /^:[^ ]+ (?:001|376) ([^ ]+) :/) { $_[HEAP]->{nick} = $1; } # We received some data, record that. $_[HEAP]->{last_traffic} = time; $_[0]->SUPER::_parseline(@_[1..$#_]); } # We ping the server if we haven't seen any traffic for 60s. use constant AUTOPING_INTERVAL => 60 * 1; # A connection is considered dead if we haven't seen any traffic von 5 +min. use constant CONNDEAD_TIMEOUT => 60 * 5; sub _start { $_[0]->SUPER::_start(@_[1..$#_]); # We have to register some eventhandler. POE::Kernel->state(autoping => \&bot_autoping); POE::Kernel->state(livecheck => \&bot_livecheck); POE::Kernel->state(irc_001 => \&irc_001); POE::Kernel->state(irc_433 => \&irc_433); POE::Kernel->state(irc_join => \&irc_join); POE::Kernel->state(irc_part => \&irc_part); POE::Kernel->state(irc_kick => \&irc_kick); POE::Kernel->state(irc_nick => \&irc_nick); # And, we have to register our interest. POE::Kernel->yield(register => qw( 001 433 join part kick nick )); # We check every 10s if we've seen traffic for AUTOPING_INTERVAL sec +onds. POE::Kernel->delay_set(autoping => 10); # A connection is considered dead after CONNDEAD_TIMEOUT seconds. POE::Kernel->delay_set(livecheck => 10); } sub connect { $_[0]->SUPER::connect(@_[1..$#_]); # Our nick. my $nick = $_[HEAP]->{nick}; # $_[HEAP]->nickgen is a coderef which returns our nick pre- or post +fixed # with C<_>s at each invocation (nick, nick_, _nick, etc.). $_[HEAP]->{nickgen} = $_[0]->permute_nick($nick); # $_[HEAP]->{channels} is a hashref which contains channel names as +keys. If # $_[HEAP]->{channels}->{"#parrot"} is true, the bot is in #parrot. $_[HEAP]->{channels} = {}; # livecheck would kill our connection if we don't "lie" about the # last_traffic seen. $_[HEAP]->{last_traffic} = time; } # If we haven't seen traffic for AUTOPING_INTERVAL seconds, we ping th +e server. sub bot_autoping { # There should be only one "instance" of autoping. POE::Kernel->alarm_remove( $_[HEAP]->{autoping_id} ) if $_[HEAP]->{a +utoping_id}; if( # We have to know the server's name (not the hostname). defined $_[HEAP]->{irc_servername} and # We can only PING if we're connected $_[HEAP]->{connected} and # PING only, if we haven't seen traffic for AUTOPING_INTERVAL seco +nds. time - $_[HEAP]->{last_traffic} >= AUTOPING_INTERVAL ) { POE::Kernel->yield(sl_login => "PING :" . $_[HEAP]->{irc_servernam +e}); } # Check again in 10s. $_[HEAP]->{autoping_id} = POE::Kernel->delay_set(autoping => 10); } # Properly mark the connection as disconnected if it's stalled. sub bot_livecheck { # There should be only one "instance" of livecheck. POE::Kernel->alarm_remove( $_[HEAP]->{livecheck_id} ) if $_[HEAP]->{ +livecheck_id}; # If we haven't seen traffic for CONNDEAD_TIMEOUT seconds... if( $_[HEAP]->{connected} and time - $_[HEAP]->{last_traffic} >= CONNDEAD_TIMEOUT ) { POE::Kernel->yield(sl_login => "QUIT"); $_[HEAP]->{connected} = 0; } # Check again in 10s. $_[HEAP]->{livecheck_id} = POE::Kernel->delay_set(livecheck => 10); } sub irc_001 { # ARG0 contains the name of the server. We have to store that in ord +er to be # able to autoping. $_[HEAP]->{irc_servername} = $_[ARG0]; } # 433: Nick taken. sub irc_433 { # So, we take the next permuted nick. my $new = $_[HEAP]->{nickgen}->(); POE::Kernel->yield(nick => $new); $_[HEAP]->{nick} = $new; } # irc_join is triggered whenever somebody joins a channel. sub irc_join { my ($mask, $channel) = @_[ARG0, ARG1]; # If the thing which joined is something without a nick (e.g. a # pseudo-server, etc.), skip. $mask =~ /^([^!]+)/ or return; # $1 is the nickname of the person who joined. if($1 eq $_[HEAP]->{nick}) { # We joined $channel. $_[HEAP]->{channels}->{$channel}++; } } # irc_part is triggered whenever somebody parts a channel. sub irc_part { my ($mask, $channel) = @_[ARG0, ARG1]; $channel =~ /^([^ ]+) ?:?(.*)/; ($channel, my $why) = ($1, defined $2 ? $2 : ""); # Because of a bug in PoCo::IRC (author notified), the PART messag +e gets # concatenated with the channel name. We have to strip that out. # Same thing like above, if the "person" who joined is special, skip +. $mask =~ /^([^!]+)/ or return; if($1 eq $_[HEAP]->{nick}) { # We left $channel. delete $_[HEAP]->{channels}->{$channel}; } } # irc_kick is triggered whenever somebody is kicked off a channel. sub irc_kick { my ($kicker, $channel, $kicked, $why) = @_[ARG0 .. $#_]; # Again, skip special things. $kicked =~ /^([^!]+)/ or return; if($1 eq $_[HEAP]->{nick}) { # We were kicked from $channel. delete $_[HEAP]->{channels}->{$channel}; } } # irc_nick is triggered whenever somebody changes his nick. sub irc_nick { my ($mask, $new) = @_[ARG0, ARG1]; # ...Skip special things... $mask =~ /^([^!]+)/ or return; if($1 eq $_[HEAP]->{nick}) { # We changed our nick. $_[HEAP]->{nick} = $new; } } # Input: A nick # Output: A coderef which returns the nick permuted upon invocation. sub permute_nick { my $n = $_[1]; my @nicks = split /\s+/, <<NICKS; ${n} ${n}_ _${n} _${n}_ ${n}__ __${n} __${n}__ _${n}__ __${n}_ ${n}___ ___${n} ___${n}___ NICKS # Ok, that's enough... :-) sub { my $nick = shift @nicks; push @nicks, $nick; return $nick; }; } package main; unless(caller) { # A small demo, straightforward. # The bot joins #test1,#test2,#test3 when it's online. # Every 3s it'll display some status information. # KICK or KILL him, the bot will update his status accordingly. POE::Session->create(inline_states => { _start => sub { POE::Component::IRC::Tracking->new("bot"); POE::Kernel->post("bot", register => qw( 376 join )); POE::Kernel->post("bot", connect => { Server => "thestars", Nick => "testlongnicktestlongnick", }); }, # End of /MOTD, e.g.: We're inside. irc_376 => sub { warn "Inside.\n"; local $_; POE::Kernel->post("bot", join => $_) for "#test1", "#test2", "#t +est3"; POE::Kernel->delay_set(info => 3); }, info => sub { # We should add nice C<POE::Kernel::call>able events to query th +is # information. my $heap = POE::Kernel->alias_resolve("bot")->get_heap; if($heap->{connected}) { warn "We are on: " . join(", ", keys %{ $heap->{channels} }) . " +\n"; warn "Our nick is: " . $heap->{nick} . "\n"; } else { warn "Not connected.\n"; } POE::Kernel->delay_set(info => 3); }, }); POE::Kernel->run; } 1;

In reply to POE::Component::IRC::Tracking by iblech

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2022-06-27 17:54 GMT
Find Nodes?
    Voting Booth?
    My most frequent journeys are powered by:

    Results (88 votes). Check out past polls.