1POE::Component::IRC::PlUusgeirn(C3o)ntributed Perl DocumPeOnEt:a:tCioomnponent::IRC::Plugin(3)
2
3
4
6 POE::Component::IRC::Plugin - Provides plugin constants and
7 documentation for POE::Component::IRC
8
10 # A simple ROT13 'encryption' plugin
11
12 package Rot13;
13
14 use strict;
15 use warnings;
16 use POE::Component::IRC::Plugin qw( :ALL );
17
18 # Plugin object constructor
19 sub new {
20 my $package = shift;
21 return bless {}, $package;
22 }
23
24 sub PCI_register {
25 my ($self, $irc) = splice @_, 0, 2;
26
27 $irc->plugin_register( $self, 'SERVER', qw(public) );
28 return 1;
29 }
30
31 # This is method is mandatory but we don't actually have anything to do.
32 sub PCI_unregister {
33 return 1;
34 }
35
36 sub S_public {
37 my ($self, $irc) = splice @_, 0, 2;
38
39 # Parameters are passed as scalar-refs including arrayrefs.
40 my $nick = ( split /!/, ${ $_[0] } )[0];
41 my $channel = ${ $_[1] }->[0];
42 my $msg = ${ $_[2] };
43
44 if (my ($rot13) = $msg =~ /^rot13 (.+)/) {
45 $rot13 =~ tr[a-zA-Z][n-za-mN-ZA-M];
46
47 # Send a response back to the server.
48 $irc->yield( privmsg => $channel => $rot13 );
49 # We don't want other plugins to process this
50 return PCI_EAT_PLUGIN;
51 }
52
53 # Default action is to allow other plugins to process it.
54 return PCI_EAT_NONE;
55 }
56
58 POE::Component::IRC's plugin system has been released separately as
59 Object::Pluggable. Gleaning at its documentation is advised. The rest
60 of this document mostly describes aspects that are specific to
61 POE::Component::IRC's use of Object::Pluggable.
62
64 Certain individuals in #PoE on MAGNet said we didn't need to bloat the
65 PoCo-IRC code...
66
67 BinGOs, the current maintainer of the module, and I heartily agreed
68 that this is a wise choice.
69
70 One example:
71
72 Look at the magnificent new feature in 3.4 -> irc_whois replies! Yes,
73 that is a feature I bet most of us have been coveting for a while, as
74 it definitely makes our life easier. It was implemented in 30 minutes
75 or so after a request, the maintainer said. I replied by saying that
76 it's a wonderful idea, but what would happen if somebody else asked for
77 a new feature? Maybe thatfeature is something we all would love to
78 have, so should it be put in the core? Plugins allow the core to stay
79 lean and mean, while delegating additional functionality to outside
80 modules. BinGOs' work with making PoCo-IRC inheritable is wonderful,
81 but what if there were 2 modules which have features that you would
82 love to have in your bot? Inherit from both? Imagine the mess...
83
84 Here comes plugins to the rescue :)
85
86 You could say Bot::Pluggable does the job, and so on, but if this
87 feature were put into the core, it would allow PoCo-IRC to be extended
88 beyond our wildest dreams, and allow the code to be shared amongst us
89 all, giving us superior bug smashing abilities.
90
91 Yes, there are changes that most of us will moan when we go update our
92 bots to use the new $irc object system, but what if we also used this
93 opportunity to improve PoCo-IRC even more and give it a lifespan until
94 Perl8 or whatever comes along? :)
95
97 The plugin system works by letting coders hook into the two aspects of
98 PoCo-IRC:
99
100 · Data received from the server
101
102 · User commands about to be sent to the server
103
104 The goal of this system is to make PoCo-IRC so easy to extend, enabling
105 it to Take Over The World! *Just Kidding*
106
107 The general architecture of using the plugins should be:
108
109 # Import the stuff...
110 use POE;
111 use POE::Component::IRC;
112 use POE::Component::IRC::Plugin::ExamplePlugin;
113
114 # Create our session here
115 POE::Session->create( ... );
116
117 # Create the IRC session here
118 my $irc = POE::Component::IRC->spawn() or die "Oh noooo! $!";
119
120 # Create the plugin
121 # Of course it could be something like $plugin = MyPlugin->new();
122 my $plugin = POE::Component::IRC::Plugin::ExamplePlugin->new( ... );
123
124 # Hook it up!
125 $irc->plugin_add( 'ExamplePlugin', $plugin );
126
127 # OOPS, we lost the plugin object!
128 my $pluginobj = $irc->plugin_get( 'ExamplePlugin' );
129
130 # We want a list of plugins and objects
131 my $hashref = $irc->plugin_list();
132
133 # Oh! We want a list of plugin aliases.
134 my @aliases = keys %{ $irc->plugin_list() };
135
136 # Ah, we want to remove the plugin
137 $plugin = $irc->plugin_del( 'ExamplePlugin' );
138
139 The plugins themselves will conform to the standard API described here.
140 What they can do is limited only by imagination and the IRC RFC's ;)
141
142 # Import the constants
143 use POE::Component::IRC::Plugin qw( :ALL );
144
145 # Our constructor
146 sub new {
147 ...
148 }
149
150 # Required entry point for PoCo-IRC
151 sub PCI_register {
152 my ($self, $irc) = @_;
153 # Register events we are interested in
154 $irc->plugin_register( $self, 'SERVER', qw( 355 kick whatever) );
155
156 # Return success
157 return 1;
158 }
159
160 # Required exit point for PoCo-IRC
161 sub PCI_unregister {
162 my ($self, $irc) = @_;
163
164 # PCI will automatically unregister events for the plugin
165
166 # Do some cleanup...
167
168 # Return success
169 return 1;
170 }
171
172 # Registered events will be sent to methods starting with IRC_
173 # If the plugin registered for SERVER - irc_355
174 sub S_355 {
175 my($self, $irc, $line) = @_;
176
177 # Remember, we receive pointers to scalars, so we can modify them
178 $$line = 'frobnicate!';
179
180 # Return an exit code
181 return PCI_EAT_NONE;
182 }
183
184 # Default handler for events that do not have a corresponding plugin
185 # method defined.
186 sub _default {
187 my ($self, $irc, $event) = splice @_, 0, 3;
188
189 print "Default called for $event\n";
190
191 # Return an exit code
192 return PCI_EAT_NONE;
193 }
194
195 Plugins can even embed their own POE sessions if they need to do fancy
196 stuff. Below is a template for a plugin which does just that.
197
198 package POE::Plugin::Template;
199
200 use POE;
201 use POE::Component::IRC::Plugin qw( :ALL );
202
203 sub new {
204 my $package = shift;
205 my $self = bless {@_}, $package;
206 return $self;
207 }
208
209 sub PCI_register {
210 my ($self, $irc) = splice @_, 0, 2;
211
212 # We store a ref to the $irc object so we can use it in our
213 # session handlers.
214 $self->{irc} = $irc;
215
216 $irc->plugin_register( $self, 'SERVER', qw(blah blah blah) );
217
218 POE::Session->create(
219 object_states => [
220 $self => [qw(_start _shutdown)],
221 ],
222 );
223
224 return 1;
225 }
226
227 sub PCI_unregister {
228 my ($self, $irc) = splice @_, 0, 2;
229 # Plugin is dying make sure our POE session does as well.
230 $poe_kernel->call( $self->{SESSION_ID} => '_shutdown' );
231 delete $self->{irc};
232 return 1;
233 }
234
235 sub _start {
236 my ($kernel, $self) = @_[KERNEL, OBJECT];
237 $self->{SESSION_ID} = $_[SESSION]->ID();
238 # Make sure our POE session stays around. Could use aliases but that is so messy :)
239 $kernel->refcount_increment( $self->{SESSION_ID}, __PACKAGE__ );
240 return;
241 }
242
243 sub _shutdown {
244 my ($kernel, $self) = @_[KERNEL, OBJECT];
245 $kernel->alarm_remove_all();
246 $kernel->refcount_decrement( $self->{SESSION_ID}, __PACKAGE__ );
247 return;
248 }
249
251 SERVER hooks
252 Hooks that are targeted toward data received from the server will get
253 the exact same arguments as if it was a normal event, look at the PoCo-
254 IRC docs for more information.
255
256 NOTE: Server methods are identified in the plugin namespace by the
257 subroutine prefix of S_*. I.e. an irc_kick event handler would be:
258
259 sub S_kick {}
260
261 The only difference is instead of getting scalars, the hook will get a
262 reference to the scalar, to allow it to mangle the data. This allows
263 the plugin to modify data *before* they are sent out to registered
264 sessions.
265
266 They are required to return one of the exit codes so PoCo-IRC will know
267 what to do.
268
269 Names of potential hooks
270
271 001
272 socketerr
273 connected
274 plugin_del
275 ...
276
277 Keep in mind that they are always lowercased. Check out the OUTPUT
278 section of POE::Component::IRC's documentation for the complete list of
279 events.
280
281 USER hooks
282 These type of hooks have two different argument formats. They are split
283 between data sent to the server, and data sent through DCC connections.
284
285 NOTE: User methods are identified in the plugin namespace by the
286 subroutine prefix of U_*. I.e. an irc_kick event handler would be:
287
288 sub U_kick {}
289
290 Hooks that are targeted to user data have it a little harder. They will
291 receive a reference to the raw line about to be sent out. That means
292 they will have to parse it in order to extract data out of it.
293
294 The reasoning behind this is that it is not possible to insert hooks in
295 every method in the $irc object, as it will become unwieldy and not
296 allow inheritance to work.
297
298 The DCC hooks have it easier, as they do not interact with the server,
299 and will receive references to the arguments specified in the DCC
300 plugin documentation regarding dcc commands.
301
302 Names of potential hooks
303
304 kick
305 dcc_chat
306 ison
307 privmsg
308 ...
309
310 Keep in mind that they are always lowercased, and are extracted from
311 the raw line about to be sent to the irc server. To be able to parse
312 the raw line, some RFC reading is in order. These are the DCC events
313 that are not given a raw line, they are:
314
315 dcc - $nick, $type, $file, $blocksize, $timeout
316 dcc_accept - $cookie, $myfile
317 dcc_resume - $cookie
318 dcc_chat - $cookie, @lines
319 dcc_close - $cookie
320
321 _default
322 If a plugin has registered for an event but doesn't have a hook method
323 defined for ir, component will attempt to call a plugin's "_default"
324 method. The first parameter after the plugin and irc objects will be
325 the handler name.
326
327 sub _default {
328 my ($self, $irc, $event) = splice @_, 0, 3;
329
330 # $event will be something like S_public or U_dcc, etc.
331 return PCI_EAT_NONE;
332 }
333
334 The "_default" handler is expected to return one of the exit codes so
335 PoCo-IRC will know what to do.
336
338 PCI_EAT_NONE
339 This means the event will continue to be processed by remaining plugins
340 and finally, sent to interested sessions that registered for it.
341
342 PCI_EAT_CLIENT
343 This means the event will continue to be processed by remaining plugins
344 but it will not be sent to any sessions that registered for it. This
345 means nothing will be sent out on the wire if it was an USER event,
346 beware!
347
348 PCI_EAT_PLUGIN
349 This means the event will not be processed by remaining plugins, it
350 will go straight to interested sessions.
351
352 PCI_EAT_ALL
353 This means the event will be completely discarded, no plugin or session
354 will see it. This means nothing will be sent out on the wire if it was
355 an USER event, beware!
356
358 Exports the return constants for plugins to use in @EXPORT_OK Also, the
359 ':ALL' tag can be used to get all of them.
360
362 POE::Component::IRC
363
364 Object::Pluggable
365
366 Object::Pluggable::Pipeline
367
368 POE::Session
369
371 Apocalypse <apocal@cpan.org>
372
373
374
375perl v5.12.2 2010-11-05 POE::Component::IRC::Plugin(3)