POE::C...:Plugin(3pm)
π POE::C...:Plugin(3pm) π
okay bestie so the line at the very top of this page is literally POE::C...:Plugin(3pm) β User Contributed Perl Documentation β POE::C...:Plugin(3pm), and we're about to unpack the whole thing together. grab a snack, we're going in πβ¨
β¨ NAME β¨
POE::Component::IRC::Plugin β it provides the plugin constants and all the documentation for POE::Component::IRC. that's the whole job. it's giving "I contain multitudes" but for plugin stuff π
πΈ SYNOPSIS πΈ
here's a whole little ROT13 "encryption" plugin, look at her go:
# A simple ROT13 'encryption' plugin
package Rot13;
use strict;
use warnings;
use POE::Component::IRC::Plugin qw( :ALL );
# Plugin object constructor
sub new {
my $package = shift;
return bless {}, $package;
}
sub PCI_register {
my ($self, $irc) = splice @_, 0, 2;
$irc->plugin_register( $self, 'SERVER', qw(public) );
return 1;
}
# This is method is mandatory but we don't actually have anything to do.
sub PCI_unregister {
return 1;
}
sub S_public {
my ($self, $irc) = splice @_, 0, 2;
# Parameters are passed as scalar-refs including arrayrefs.
my $nick = ( split /!/, ${ $_[0] } )[0];
my $channel = ${ $_[1] }->[0];
my $msg = ${ $_[2] };
if (my ($rot13) = $msg =~ /^rot13 (.+)/) {
$rot13 =~ tr[a-zA-Z][n-za-mN-ZA-M];
# Send a response back to the server.
$irc->yield( privmsg => $channel => $rot13 );
# We don't want other plugins to process this
return PCI_EAT_PLUGIN;
}
# Default action is to allow other plugins to process it.
return PCI_EAT_NONE;
}
iconic. no notes. π₯
π DESCRIPTION π
so like, POE::Component::IRC's plugin system got released separately as Object::Pluggable. and honestly? you should go read its documentation, that's the advised move, bestie. the rest of this doc mostly covers the stuff that's specific to how POE::Component::IRC uses Object::Pluggable. periodt.
π HISTORY π
okay storytime, because the lore matters π«Ά
some individuals in #PoE on MAGNet were like "we do NOT need to bloat the PoCo-IRC code..."
and BinGOs, who is the current maintainer of the module, plus the author, hearily agreed that this is a wise choice. (their words, and honestly, correct.)
one example they give:
look at the magnificent new feature in 3.4 β irc_whois replies! yes, that's a feature plenty of us have been coveting for a while, because it definitely makes life easier. it got implemented in like 30 minutes or so after a request, the maintainer said. the reply was basically "wonderful idea, but what happens if somebody else asks for a new feature? maybe that feature is something we'd all love, so should it go in the core?" and the answer is: plugins let the core stay lean and mean while delegating extra functionality to outside modules. BinGOs' work making PoCo-IRC inheritable is wonderful, but imagine there were 2 modules with features you'd love in your bot β inherit from both?? imagine the mess... π
here comes plugins to the rescue :)
you could say Bot::Pluggable does the job and so on, but if this feature were put into the core, it would let PoCo-IRC be extended beyond our wildest dreams, and let the code be shared amongst us all, giving us superior bug smashing abilities. πβ¨
yes, there are changes most of us will moan about when we go update our bots to use the new $irc object system β but what if we also used this opportunity to improve PoCo-IRC even more and give it a lifespan until Perl8 or whatever comes along? :)
π DESCRIPTION π (yes, there's another one, she's the main character now)
the plugin system works by letting coders hook into the two aspects of PoCo-IRC:
- Data received from the server
- User commands about to be sent to the server
the goal of this system is to make PoCo-IRC so easy to extend that it can Take Over The World! Just Kidding π
the general architecture of using the plugins should be:
# Import the stuff...
use POE;
use POE::Component::IRC;
use POE::Component::IRC::Plugin::ExamplePlugin;
# Create our session here
POE::Session->create( ... );
# Create the IRC session here
my $irc = POE::Component::IRC->spawn() or die "Oh noooo! $!";
# Create the plugin
# Of course it could be something like $plugin = MyPlugin->new();
my $plugin = POE::Component::IRC::Plugin::ExamplePlugin->new( ... );
# Hook it up!
$irc->plugin_add( 'ExamplePlugin', $plugin );
# OOPS, we lost the plugin object!
my $pluginobj = $irc->plugin_get( 'ExamplePlugin' );
# We want a list of plugins and objects
my $hashref = $irc->plugin_list();
# Oh! We want a list of plugin aliases.
my @aliases = keys %{ $irc->plugin_list() };
# Ah, we want to remove the plugin
$plugin = $irc->plugin_del( 'ExamplePlugin' );
the plugins themselves will conform to the standard API described here. what they can do is limited only by imagination and the IRC RFCs ;)
# Import the constants
use POE::Component::IRC::Plugin qw( :ALL );
# Our constructor
sub new {
...
}
# Required entry point for PoCo-IRC
sub PCI_register {
my ($self, $irc) = @_;
# Register events we are interested in
$irc->plugin_register( $self, 'SERVER', qw( 355 kick whatever) );
# Return success
return 1;
}
# Required exit point for PoCo-IRC
sub PCI_unregister {
my ($self, $irc) = @_;
# PCI will automatically unregister events for the plugin
# Do some cleanup...
# Return success
return 1;
}
# Registered events will be sent to methods starting with IRC_
# If the plugin registered for SERVER - irc_355
sub S_355 {
my($self, $irc, $line) = @_;
# Remember, we receive pointers to scalars, so we can modify them
$$line = 'frobnicate!';
# Return an exit code
return PCI_EAT_NONE;
}
# Default handler for events that do not have a corresponding plugin
# method defined.
sub _default {
my ($self, $irc, $event) = splice @_, 0, 3;
print "Default called for $event\n";
# Return an exit code
return PCI_EAT_NONE;
}
plugins can even embed their own POE sessions if they need to do fancy stuff. below is a template for a plugin which does just that. π§
package POE::Plugin::Template;
use POE;
use POE::Component::IRC::Plugin qw( :ALL );
sub new {
my $package = shift;
my $self = bless {@_}, $package;
return $self;
}
sub PCI_register {
my ($self, $irc) = splice @_, 0, 2;
# We store a ref to the $irc object so we can use it in our
# session handlers.
$self->{irc} = $irc;
$irc->plugin_register( $self, 'SERVER', qw(blah blah blah) );
POE::Session->create(
object_states => [
$self => [qw(_start _shutdown)],
],
);
return 1;
}
sub PCI_unregister {
my ($self, $irc) = splice @_, 0, 2;
# Plugin is dying make sure our POE session does as well.
$poe_kernel->call( $self->{SESSION_ID} => '_shutdown' );
delete $self->{irc};
return 1;
}
sub _start {
my ($kernel, $self) = @_[KERNEL, OBJECT];
$self->{SESSION_ID} = $_[SESSION]->ID();
# Make sure our POE session stays around. Could use aliases but that is so messy :)
$kernel->refcount_increment( $self->{SESSION_ID}, __PACKAGE__ );
return;
}
sub _shutdown {
my ($kernel, $self) = @_[KERNEL, OBJECT];
$kernel->alarm_remove_all();
$kernel->refcount_decrement( $self->{SESSION_ID}, __PACKAGE__ );
return;
}
π EVENT TYPES π
π¦ SERVER hooks π¦
hooks that are targeted toward data received from the server get the exact same arguments as if it was a normal event. go look at the PoCo-IRC docs for more info, bestie.
NOTE: Server methods are identified in the plugin namespace by the subroutine prefix ofS_*. I.e. anirc_kickevent handler would be:
sub S_kick {}
the only difference is that instead of getting scalars, the hook gets a reference to the scalar, so it can mangle the data. this lets the plugin modify data before it gets sent out to registered sessions. π
they are required to return one of the exit codes so PoCo-IRC knows what to do.
names of potential hooks:
001
socketerr
connected
plugin_del
...
keep in mind that they are always lowercased. check out the OUTPUT EVENTS section of POE::Component::IRC's documentation for the complete list of events.
πΈ USER hooks πΈ
these type of hooks have two different argument formats. they're split between data sent to the server, and data sent through DCC connections.
NOTE: User methods are identified in the plugin namespace by the subroutine prefix ofU_*. I.e. anirc_kickevent handler would be:
sub U_kick {}
hooks that are targeted to user data have it a little harder. they receive a reference to the raw line about to be sent out. that means they have to parse it in order to extract data out of it. π
the reasoning behind this is that it's not possible to insert hooks in every method in the $irc object, because it would become unwieldy and wouldn't allow inheritance to work.
the DCC hooks have it easier, since they don't interact with the server, and they receive references to the arguments specified in the DCC plugin documentation regarding dcc commands.
names of potential hooks:
kick
dcc_chat
ison
privmsg
...
keep in mind that they are always lowercased, and are extracted from the raw line about to be sent to the irc server. to be able to parse the raw line, some RFC reading is in order, bestie β no skipping. these are the DCC events that are not given a raw line, they are:
dcc - $nick, $type, $file, $blocksize, $timeout
dcc_accept - $cookie, $myfile
dcc_resume - $cookie
dcc_chat - $cookie, @lines
dcc_close - $cookie
π _default π
if a plugin has registered for an event but doesn't have a hook method defined for it, the component will attempt to call a plugin's "_default" method. the first parameter after the plugin and irc objects will be the handler name.
sub _default {
my ($self, $irc, $event) = splice @_, 0, 3;
# $event will be something like S_public or U_dcc, etc.
return PCI_EAT_NONE;
}
the "_default" handler is expected to return one of the exit codes so PoCo-IRC will know what to do. π«Ά
okay that's part 1, and there is more coming, so don't go anywhere β part 2 is right behind this one πβ¨
π₯ EXIT CODES π₯
okay bestie, listen UP, because this is the part where you pick what happens to the event after your plugin gets its little paws on it. Every handler you write has to hand back one of these bad boys, and which one you pick changes everything. Choose wisely, no cap. π«Ά
π« PCI_EAT_NONE
The chill one. Nothing gets eaten, nothing gets skipped. The event keeps bubbling along through all the remaining plugins, and then β after all that β it gets handed off to whatever sessions signed up for it. This is your "I looked at it, I'm not touching it, carry on" energy. β¨
πΈ PCI_EAT_CLIENT
Ooh okay so this one is spicy. The event does keep getting processed by the remaining plugins β they all still get their turn β but it will not be sent to any sessions that registered for it.
Which means: if this was an USER event, nothing goes out on the wire. Like, nothing. Gone. π
β οΈ beware! This one bites. If you didn't mean to swallow the event whole, don't reach for it.
π PCI_EAT_PLUGIN
Okay this one does the opposite of the last one, iconic honestly. The event stops dead here β no remaining plugins get to see it β and it goes straight to the interested sessions.
So the plugins after you are left on read π but the sessions still get their event.
π₯ PCI_EAT_ALL
The nuclear option. π This event is completely discarded. No plugin sees it. No session sees it. It's giving black hole, it's giving void, it's giving what event, bestie, I don't know her.
And yes β if it was an USER event, nothing will be sent out on the wire. beware! π³
β οΈ seriously, beware. Double beware. PCI_EAT_ALL is not a joke, that event is never coming back.
π EXPORTS π
This bad boy exports all the return constants β you know, the PCI_EAT_* ones from above β so your plugin can actually use them in @EXPORT_OK. π
And because we're generous like that, there's also a :ALL tag you can use to scoop up every single one of them at once. Periodt. β¨
use POE::Component::IRC::Plugin qw(:ALL);
π SEE ALSO π
go read these too, they're all part of the same little universe, iykyk π¦
POE::Component::IRCObject::PluggableObject::Pluggable::PipelinePOE::Session
π AUTHOR π
Apocalypse <apocal@cpan.org> β the main character who wrote all of this. absolute legend, we love them for it π
and that's the whole page bestie, you made it!! π this was POE::C...:Plugin(3pm) from the perl v5.40.1 docs, dated 2025-08-21, when the generous humans at User Contributed Perl Documentation blessed us with it. go forth and eat some events, but likeβ¦ carefully. π«Άπ
β¨
π¦ where this page comes from
- ubuntu resolute: libpoe-component-irc-perl 6.95+dfsg-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libpoe-component-irc-perl 6.95+dfsg-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms