1POE::Component::IRC::PlUusgeirn(C3o)ntributed Perl DocumPeOnEt:a:tCioomnponent::IRC::Plugin(3)
2
3
4

ABSTRACT

6               Provides plugin documentation for PoCo-IRC
7

CHANGES

9       0.08
10
11               Added EXAMPLES section.
12
13       0.07
14
15               The plugin sytem has changed to use L<POE::Component::IRC::Pipeline> now.  See its documentation
16               for information about the underlying operations of the pipeline.
17
18               There's a new method, plugin_order, which returns an array reference of the plugins in the pipeline
19               in the order in which they are executed.
20
21               There's a new method, pipeline, which returns the POE::Component::IRC::Pipeline object so you can
22               deal with its finer-tuned controls yourself.
23
24               The _plugin_unregister_do method is no more.
25
26       0.06
27
28               Updated _plugin_process so that it runs plugin method calls in an 'eval'. Rogue plugins shouldn't be
29               able to crash the component now.
30
31               If a plugin doesn't have a event handler method defined now, the component will try to call a
32               _default() handler instead.
33
34       0.05
35
36               Realized that there would be collision between USER/SERVER methods, so made it distinct by using S_* and U_*
37               Clarified the documentation to stress that 'irc_' is not required for event names
38               Changed the description of the 2 new events to stress that they are sent *after* the action is done
39
40       0.04
41
42               Changed _plugin_register/unregister to non-private methods
43
44       0.03
45
46               As per perigrin's suggestion, added 2 new event types to monitor plugin add/del
47               Updated the name from PoCo-IRC-Plugins to PoCo-IRC-Plugin
48               Updated return value ( PCI_EAT_PLUGINS to PCI_EAT_PLUGIN )
49               Updated plugin_del to also accept the plugin object instead of a name
50
51       0.02
52
53               Modified plugin_del() so it returns the plugin object
54
55       0.01
56
57               Initial release
58

Why do we need this?

60       Certain individuals in #PoE on MAGNet said we didn't need to bloat the
61       PoCo-IRC code...
62
63       BinGOs, the current maintainer of the module, and I heartily agreed
64       that this is a wise choice.
65
66       One example:
67
68               Look at the magnificent new feature in 3.4 -> irc_whois replies! Yes, that is a feature I bet
69               most of us have been coveting for a while, as it definitely makes our life easier. It was
70               implemented in 30 minutes or so after a request, the maintainer said. I replied by saying that
71               it's a wonderful idea, but what would happen if somebody else asked for a new feature? Maybe that
72               feature is something we all would love to have, so should it be put in the core? Plugins allow the
73               core to stay lean and mean, while delegating additional functionality to outside modules. BinGOs' work
74               with making PoCo-IRC inheritable is wonderful, but what if there were 2 modules which have features
75               that you would love to have in your bot? Inherit from both? Imagine the mess...
76
77               Here comes plugins to the rescue :)
78
79       You could say Bot::Pluggable does the job, and so on, but if this fea‐
80       ture were put into the core, it would allow PoCo-IRC to be extended
81       beyond our wildest dreams, and allow the code to be shared amongst us
82       all, giving us superior bug smashing abilities.
83
84       Yes, there are changes that most of us will moan when we go update our
85       bots to use the new $irc object system, but what if we also used this
86       opportunity to improve PoCo-IRC even more and give it a lifespan until
87       Perl8 or whatever comes along? :)
88

DESCRIPTION

90       This is the document coders/users should refer to when using/developing
91       plugins for POE::Component::IRC.
92
93       The plugin system works by letting coders hook into the two aspects of
94       PoCo-IRC:
95
96               Data received from the server
97               User commands about to be sent to the server
98
99       The goal of this system is to make PoCo-IRC so easy to extend, enabling
100       it to Take Over The World! *Just Kidding*
101
102       The general architecture of using the plugins should be:
103
104               # Import the stuff...
105               use POE;
106               use POE::Component::IRC;
107               use POE::Component::IRC::Plugin::ExamplePlugin;
108
109               # Create our session here
110               POE::Session->create( ... );
111
112               # Create the IRC session here
113               my $irc = POE::Component::IRC->spawn() or die 'Nooo!';
114
115               # Create the plugin
116               # Of course it could be something like $plugin = MyPlugin->new();
117               my $plugin = POE::Component::IRC::Plugin::ExamplePlugin->new( ... );
118
119               # Hook it up!
120               $irc->plugin_add( 'ExamplePlugin', $plugin );
121
122               # OOPS, we lost the plugin object!
123               my $pluginobj = $irc->plugin_get( 'ExamplePlugin' );
124
125               # We want a list of plugins and objects
126               my $hashref = $irc->plugin_list();
127
128               # Oh! We want a list of plugin aliases.
129               my @aliases = keys %{ $irc->plugin_list() };
130
131               # Ah, we want to remove the plugin
132               $plugin = $irc->plugin_del( 'ExamplePlugin' );
133
134       The plugins themselves will conform to the standard API described here.
135       What they can do is limited only by imagination and the IRC RFC's ;)
136
137               # Import the constants
138               use POE::Component::IRC::Plugin qw( :ALL );
139
140               # Our constructor
141               sub new {
142                       ...
143               }
144
145               # Required entry point for PoCo-IRC
146               sub PCI_register {
147                       my( $self, $irc ) = @_;
148
149                       # Register events we are interested in
150                       $irc->plugin_register( $self, 'SERVER', qw( 355 kick whatever) );
151
152                       # Return success
153                       return 1;
154               }
155
156               # Required exit point for PoCo-IRC
157               sub PCI_unregister {
158                       my( $self, $irc ) = @_;
159
160                       # PCI will automatically unregister events for the plugin
161
162                       # Do some cleanup...
163
164                       # Return success
165                       return 1;
166               }
167
168               # Registered events will be sent to methods starting with IRC_
169               # If the plugin registered for SERVER - irc_355
170               sub S_355 {
171                       my( $self, $irc, $line ) = @_;
172
173                       # Remember, we receive pointers to scalars, so we can modify them
174                       $$line = 'frobnicate!';
175
176                       # Return an exit code
177                       return PCI_EAT_NONE;
178               }
179
180               # Default handler for events that do not have a corresponding plugin method defined.
181               sub _default {
182                       my( $self, $irc, $event ) = splice @_, 0, 3;
183
184                       print "Default called for $event\n";
185
186                       # Return an exit code
187                       return PCI_EAT_NONE;
188               }
189

Available methods to use on the $irc object

191       pipeline
192
193               This method returns (or creates) the pipeline object into which plugins are stored.
194
195       plugin_add
196
197               Accepts two arguments:
198                       The alias for the plugin
199                       The actual plugin object
200
201               The alias is there for the user to refer to it, as it is possible to have multiple
202               plugins of the same kind active in one PoCo-IRC object.
203
204               This method goes through the pipeline's push() method.
205
206               This method will call $plugin->PCI_register( $irc )
207
208               Returns the number of plugins now in the pipeline if plugin was initialized, undef
209               if not.
210
211       plugin_get
212
213               Accepts one argument:
214                       The alias for the plugin
215
216               This method goes through the pipeline's get() method.
217
218               Returns the plugin object if it was found, undef if not.
219
220       plugin_del
221
222               Accepts one argument:
223                       The alias for the plugin or the plugin object itself
224
225               This method goes through the pipeline's remove() method.
226
227               This method will call $plugin->PCI_unregister( $irc )
228
229               Returns the plugin object if the plugin was removed, undef if not.
230
231       plugin_list
232
233               Has no arguments.
234
235               Returns a hashref of plugin objects, keyed on alias, or an empty list if there are no
236               plugins loaded.
237
238       plugin_order
239
240               Has no arguments.
241
242               Returns an arrayref of plugin objects, in the order which they are encountered in the
243               pipeline.
244
245       plugin_register
246
247               Accepts the following arguments:
248                       The plugin object
249                       The type of the hook ( 'SERVER' or 'USER' )
250                       The event name(s) to watch
251
252               The event names can be as many as possible, or an arrayref. They correspond
253               to the irc_* events listed in PoCo-IRC, and naturally, arbitrary events too.
254
255               You do not need to supply events with irc_ in front of them, just the names.
256
257               It is possible to register for all events by specifying 'all' as an event.
258
259               Returns 1 if everything checked out fine, undef if something's seriously wrong
260
261       plugin_unregister
262
263               Accepts the following arguments:
264                       The plugin object
265                       The type of the hook ( 'SERVER' or 'USER' )
266                       The event name(s) to unwatch
267
268               The event names can be as many as possible, or an arrayref. They correspond
269               to the irc_* events listed in PoCo-IRC, and naturally, arbitrary events too.
270
271               You do not need to supply events with irc_ in front of them, just the names.
272
273               Returns 1 if all the event name(s) was unregistered, undef if some was not found
274

New SERVER events available to PoCo-IRC

276       irc_plugin_add
277
278       This event will be triggered after a plugin is added. It receives two
279       arguments, the first being the plugin name, and the second being the
280       plugin object.
281
282       irc_plugin_del
283
284       This event will be triggered after a plugin is deleted. It receives two
285       arguments, the first being the plugin name, and the second being the
286       plugin object.
287

Event arguments

289       SERVER hooks
290
291       Hooks that are targeted toward data received from the server will get
292       the exact same arguments as if it was a normal event, look at the PoCo-
293       IRC docs for more information.
294
295               NOTE: Server methods are identified in the plugin namespace by the subroutine prefix
296               of S_*. I.e. an irc_kick event handler would be:
297
298               sub S_kick {}
299
300       The only difference is instead of getting scalars, the hook will get a
301       reference to the scalar, to allow it to mangle the data. This allows
302       the plugin to modify data *before* they are sent out to registered ses‐
303       sions.
304
305       They are required to return one of the exit codes so PoCo-IRC will know
306       what to do.
307
308       Names of potential hooks
309
310               001
311               socketerr
312               connected
313               plugin_del
314
315       Keep in mind that they are always lowercased, check out the POE::Compo‐
316       nent::IRC manpage and look at the Important Events section for the com‐
317       plete list of names.
318
319       USER hooks
320
321       These type of hooks have two different argument formats. They are split
322       between data sent to the server, and data sent through DCC connections.
323
324               NOTE: User methods are identified in the plugin namespace by the subroutine prefix
325               of U_*. I.e. an irc_kick event handler would be:
326
327               sub U_kick {}
328
329       Hooks that are targeted to user data have it a little harder. They will
330       receive a reference to the raw line about to be sent out. That means
331       they will have to parse it in order to extract data out of it.
332
333       The reasoning behind this is that it is not possible to insert hooks in
334       every method in the $irc object, as it will become unwieldy and not
335       allow inheritance to work.
336
337       The DCC hooks have it easier, as they do not interact with the server,
338       and will receive references to the arguments specified in the PoCo-IRC
339       pod regarding dcc commands.
340
341       Names of potential hooks
342
343               kick
344               dcc_chat
345               ison
346               privmsg
347
348       Keep in mind that they are always lowercased, and are extracted from
349       the raw line about to be sent to the irc server. To be able to parse
350       the raw line, some RFC reading is in order. These are the DCC events
351       that are not given a raw line, they are:
352
353               dcc             -       $nick, $type, $file, $blocksize
354               dcc_accept      -       $cookie, $myfile
355               dcc_resume      -       $cookie
356               dcc_chat        -       $cookie, @lines
357               dcc_close       -       $cookie
358
359       _default
360
361       If a plugin doesn't have a specific hook method defined for an event,
362       the component will attempt to call a plugin's _default() method. The
363       first parameter after the plugin and irc objects will be the handler
364       name.
365
366               sub _default {
367                 my ($self,$irc,$event) = splice @_, 0, 3;
368
369                 # $event will be something like S_public or U_dcc, etc.
370                 return PCI_EAT_NONE;
371               }
372
373       The _default() handler is expected to return one of the exit codes so
374       PoCo-IRC will know what to do.
375

Exit Codes

377       PCI_EAT_NONE
378
379               This means the event will continue to be processed by remaining plugins and
380               finally, sent to interested sessions that registered for it.
381
382       PCI_EAT_CLIENT
383
384               This means the event will continue to be processed by remaining plugins but
385               it will not be sent to any sessions that registered for it. This means nothing
386               will be sent out on the wire if it was an USER event, beware!
387
388       PCI_EAT_PLUGIN
389
390               This means the event will not be processed by remaining plugins, it will go
391               straight to interested sessions.
392
393       PCI_EAT_ALL
394
395               This means the event will be completely discarded, no plugin or session will see it. This
396               means nothing will be sent out on the wire if it was an USER event, beware!
397

Plugin ordering system

399       See POE::Component::IRC::Pipeline
400

EXPORT

402               Exports the return constants for plugins to use in @EXPORT_OK
403               Also, the ':ALL' tag can be used to get all of them
404

EXAMPLES

406       A simple ROT13 'encryption' plugin
407             package Rot13;
408
409             use strict qw(subs vars refs);    # Make sure we can't mess up
410             use warnings FATAL => 'all';
411             use POE::Component::IRC::Plugin qw( :ALL );
412
413             # Plugin object constructor
414             sub new {
415               my $package = shift;
416               return bless {}, $package;
417             }
418
419             sub PCI_register {
420               my ( $self, $irc ) = splice @_, 0, 2;
421
422               $irc->plugin_register( $self, 'SERVER', qw(public) );
423               return 1;
424             }
425
426             # This is method is mandatory but we don't actually have anything to do.
427             sub PCI_unregister {
428               return 1;
429             }
430
431             sub S_public {
432               my ( $self, $irc ) = splice @_, 0, 2;
433
434               # Parameters are passed as scalar-refs including arrayrefs.
435               my $nick    = ( split /!/, ${ $_[0] } )[0];
436               my $channel = ${ $_[1] }->[0];
437               my $msg     = ${ $_[2] };
438
439               if ( my ($rot13) = $msg =~ /^rot13 (.+)/ ) {
440                   $rot13 =~ tr[a-zA-Z][n-za-mN-ZA-M];
441
442                   # Send a response back to the server.
443                   $irc->yield( privmsg => $channel => $rot13 );
444                   return PCI_EAT_PLUGIN;    # We don't want other plugins to process this
445               }
446
447               return PCI_EAT_NONE; # Default action is to allow other plugins to process it.
448             }
449
450       A template for a plugin with it's own POE::Session
451             package POE-Plugin-Template;
452
453             use POE;
454             use POE::Component::IRC::Plugin qw( :ALL );
455
456             sub new {
457               my $package = shift;
458               my $self = bless {@_}, $package;
459               return $self;
460             }
461
462             sub PCI_register {
463               my ( $self, $irc ) = splice @_, 0, 2;
464
465               # We store a ref to the $irc object so we can use it in our
466               # session handlers.
467               $self->{irc} = $irc;
468
469               $irc->plugin_register( $self, 'SERVER', qw(blah blah blah) );
470
471               $self->{SESSION_ID} = POE::Session->create(
472                   object_states => [
473                       $self => [qw(_start _shutdown)],
474                   ],
475               )->ID();
476
477               return 1;
478             }
479
480             sub PCI_unregister {
481               my ( $self, $irc ) = splice @_, 0, 2;
482               # Plugin is dying make sure our POE session does as well.
483               $poe_kernel->call( $self->{SESSION_ID} => '_shutdown' );
484               delete $self->{irc};
485               return 1;
486             }
487
488             sub _start {
489               my ( $kernel, $self ) = @_[ KERNEL, OBJECT ];
490               $self->{SESSION_ID} = $_[SESSION]->ID();
491               # Make sure our POE session stays around. Could use aliases but that is so messy :)
492               $kernel->refcount_increment( $self->{SESSION_ID}, __PACKAGE__ );
493               undef;
494             }
495
496             sub _shutdown {
497               my ($kernel, $self) = @_[ KERNEL, OBJECT ];
498               $kernel->alarm_remove_all();
499               $kernel->refcount_decrement( $self->{SESSION_ID}, __PACKAGE__ );
500               undef;
501             }
502

SEE ALSO

504       POE::Component::IRC
505
506       POE::Component::IRC::Pipeline
507
508       POE::Session
509

AUTHOR

511       Apocalypse <apocal@cpan.org>
512

PROPS

514       The idea is heavily borrowed from X-Chat, BIG thanks goes out to the
515       genius that came up with the EAT_* system :)
516
517
518
519perl v5.8.8                       2005-10-25    POE::Component::IRC::Plugin(3)
Impressum