1NAME
2 POE::Component::Syndicator - A POE component base class which implements
3 the Observer pattern
4
5SYNOPSIS
6 package POE::Component::IRC;
7
8 use strict;
9 use warnings;
10 use POE;
11 use base 'POE::Component::Syndicator';
12
13 # our constructor
14 sub spawn {
15 my ($package, %args) = @_;
16
17 # process arguments...
18
19 my $self = bless \%args, $package;
20
21 # set up our plugin system and POE session
22 $self->_syndicator_init(
23 prefix => 'irc_',
24 reg_prefix => 'PCI_',
25 types => [SERVER => 'S', USER => 'U'],
26 object_states => [qw(
27 syndicator_started
28 shutdown
29 )],
30 );
31
32 return $self;
33 }
34
35 sub syndicator_started {
36 my ($kernel, $self) = @_[KERNEL, OBJECT];
37
38 # connect to a server, etc...
39 }
40
41 # plugin handler for SERVER event 'hlagh'
42 sub S_hlagh {
43 # ...
44 }
45
46 sub shutdown {
47 my ($kernel, $self) = @_[KERNEL, OBJECT];
48
49 # disconnect from a server, etc...
50
51 # shut down the syndicator
52 $self->_syndicator_destroy();
53 }
54
55DESCRIPTION
56 POE::Component::Syndicator is a base class for POE components which need
57 to handle a persistent resource (e.g. a connection to an IRC server) for
58 one or more sessions in an extendable way.
59
60 This module (as well as Object::Pluggable, which this module inherits
61 from) was born out of POE::Component::IRC, the guts of which quickly
62 spread to other POE components. Now they can all inherit from this
63 module instead.
64
65 The component provides an event queue, which can be managed with the
66 methods documented below. It handles delivery of events to the object
67 itself, all interested plugins, and all interested sessions.
68
69 Component lifetime
70 You start by calling "_syndicator_init", which will create a POE session
71 with your object as its heap, and a few event handlers installed. The
72 events described in "Local events" delimit the start and end of the
73 session's lifetime. In between those, interested plugins and sessions
74 will receive various events, usually starting with
75 "syndicator_registered". In this phase, your subclass and plugins can
76 call the methods and send the events documented below. When the
77 component has been shut down, sessions (but not plugins) will receive a
78 "syndicator_shutdown" event. After this, the component will become
79 unusable.
80
81 A note on events
82 In this document, an *event* (unless explicitly referred to as a *POE
83 event*) is defined as a message originating from
84 POE::Component::Syndicator, delivered to plugins (and the subclass) via
85 plugin methods and to registered sessions as POE events.
86
87 Interested sessions are considered consumers only, so they always
88 receive copies of event arguments, whereas interested plugins and
89 subclasses receive scalar references to them. This allows them to alter,
90 add, or remove event arguments before sessions (or even other plugins)
91 receive them. For more information about plugins, see
92 Object::Pluggable's documentation. A subclass does not have to register
93 for plugin events.
94
95 Two event types are supported: SERVER and USER, though their names can
96 be overriden (see "_syndicator_init").
97
98 SERVER events
99 These represent data received from the network or some other outside
100 resource (usually a server, hence the default name).
101
102 SERVER events are generated by the "send_event*" methods. These events
103 are delivered to the subclass and plugins (method "S_foo") and
104 interested sessions (event "syndicator_foo").
105
106 USER events
107 These represent commands about to be sent to a server or some other
108 resource.
109
110 USER events are generated by "send_user_event". In addition, all POE
111 events sent to this component's session (e.g. with "yield") which do not
112 have a handler will generate corresponding USER events. USER events are
113 considered more private, so they are only delivered to the subclass and
114 plugins, not to sessions.
115
116PRIVATE METHODS
117 The following methods should only be called by a subclass.
118
119 "_syndicator_init"
120 You should call this in your constructor. It initializes
121 Object::Pluggable, creates the Syndicator's POE session, and calls the
122 "syndicator_started" POE events. It takes the following arguments:
123
124 'prefix', a prefix for all your event names, when sent to interested
125 sessions. If you don't supply this, Object::Pluggable's default
126 ('pluggable') will be used.
127
128 'reg_prefix', the prefix for the "register()"/"unregister()" plugin
129 methods If you don't supply this, Object::Pluggable's default
130 ('plugin_') will be used.
131
132 'debug', a boolean, if true, will cause a warning to be printed every
133 time a plugin event handler raises an exception.
134
135 'types', a 2-element arrayref of the types of events that your component
136 will support, or a 4-element (2 pairs) arrayref where the event types
137 are keys and their abbrevations (used as plugin event method prefixes)
138 are values (see "A note on events" and Object::Pluggable for more
139 information). The two event types are fundamentally different, so make
140 sure you supply them in the right order. If you don't provide this
141 argument, "[ SERVER => 'S', USER => 'U' ]" will be used.
142
143 'register_signal', the name of the register signal (see "SIGNALS").
144 Defaults to 'SYNDICATOR_REGISTER'.
145
146 'shutdown_signal', the name of the shutdown signal (see "SIGNALS").
147 Defaults to 'SYNDICATOR_SHUTDOWN'.
148
149 'object_states' an arrayref of additional object states to add to the
150 POE session. Same as the 'object_states' argument to POE::Session's
151 "create" method. You'll want to add a handler for at least the
152 "syndicator_started" event.
153
154 'options', a hash of options for POE::Session's constructor.
155
156 If you call "_syndicator_init" from inside another POE session, the
157 component will automatically register that session as wanting all
158 events. That session will first receive a "syndicator_registered" event.
159
160 "_syndicator_destroy"
161 Call this method when you want Syndicator to clean up (delete all
162 plugins, etc) and make sure it won't keep the POE session alive after
163 all remaining events have been processed. A "syndicator_shutdown" event
164 (or similar, depending on the prefix you chose) will be generated. Any
165 argument passed to "_syndicator_destroy" will be passed along with that
166 event.
167
168 Note: this method will clear all alarms for the POE session.
169
170PUBLIC METHODS
171 "session_id"
172 Returns the component's POE session id.
173
174 "session_alias"
175 Returns the component's POE session alias.
176
177 "yield"
178 This method provides an alternative, object-based means of posting
179 events to the component. First argument is the event to post, following
180 arguments are sent as arguments to the resultant post.
181
182 "call"
183 This method provides an alternative, object-based means of calling
184 events to the component. First argument is the event to call, following
185 arguments are sent as arguments to the resultant call.
186
187 "send_event"
188 Adds a new SERVER event onto the end of the queue. The event will be
189 processed after other pending events, if any. First argument is an event
190 name, the rest are the event arguments.
191
192 $component->send_event('irc_public, 'foo!bar@baz.com', ['#mychan'], 'message');
193
194 "send_event_next"
195 Adds a new SERVER event to the start of the queue. The event will be the
196 next one to be processed. First argument is an event name, the rest are
197 the event arguments.
198
199 "send_event_now"
200 Sends a new SERVER event immediately. Execution of the current POE event
201 will be suspended (i.e. this call will block) until the new event has
202 been processed by the component class and all plugins. First argument is
203 an event name, the rest are the event arguments.
204
205 "send_user_event"
206 Sends a new USER event immediately. You should call this before every
207 command you send to your remote server/resource. Only the subclass and
208 plugins will see this event. Takes two arguments, an event name and an
209 arrayref of arguments. Returns one of the "EAT" constants listed in
210 Object::Pluggable::Constants. After this method returns, the arrayref's
211 contents may have been modified by the subclass or plugins.
212
213 $component->send_user_event('PRIVMSG', '#mychan', 'message');
214
215 "delay"
216 This method provides a way of posting delayed events to the component.
217 The first argument is an arrayref consisting of the delayed command to
218 post and any command arguments. The second argument is the time in
219 seconds that one wishes to delay the command being posted.
220
221 my $alarm_id = $component->delay(['mode', $channel, '+o', $dude], 60);
222
223 "delay_remove"
224 This method removes a previously scheduled delayed event from the
225 component. Takes one argument, the "alarm_id" that was returned by a
226 "delay" method call. Returns an arrayref of arguments to the event that
227 was originally requested to be delayed.
228
229 my $arrayref = $component->delay_remove($alarm_id);
230
231EVENTS
232 Local events
233 The component will send the following POE events to its session.
234
235 "syndicator_started"
236 Called after the session has been started (like "_start" in POE::Kernel.
237 This is where you should do your POE-related setup work such as adding
238 new event handlers to the session.
239
240 "syndicator_stopped"
241 Called right before the session is about to die (like "_stop" in
242 POE::Kernel).
243
244 Input events
245 Other POE sessions can send the following POE events to the Syndicator's
246 session.
247
248 "register"
249 Takes any amount of arguments: a list of event names that your session
250 wants to listen for, minus the prefix (specified in "_syndicator_init"
251 in "syndicator_init").
252
253 $kernel->post('my syndicator', 'register', qw(join part quit kick));
254
255 Registering for the special event 'all' will cause it to send all events
256 to your session. Calling it with no event names is equivalent to calling
257 it with 'all' as an argumente.
258
259 Registering will generate a "syndicator_registered" event that your
260 session can trap.
261
262 Registering with multiple component sessions can be tricky, especially
263 if one wants to marry up sessions/objects, etc. Check the SIGNALS
264 section for an alternative method of registering with multiple
265 components.
266
267 "unregister"
268 Takes any amount of arguments: a list of event names which you *don't*
269 want to receive. If you've previously done a "register" for a particular
270 event which you no longer care about, this event will tell the component
271 to stop sending them to you. (If you haven't, it just ignores you. No
272 big deal.) Calling it with no event names is equivalent to calling it
273 with 'all' as an argument.
274
275 If you have registered for the special event 'all', attempting to
276 unregister individual events will not work. This is a 'feature'.
277
278 "shutdown"
279 By default, POE::Component::Syndicator sessions never go away. You can
280 send its session a "shutdown" event manually to make it delete itself.
281 Terminating multiple Syndicators can be tricky. Check the "SIGNALS"
282 section for a method of doing that.
283
284 "_default"
285 Any POE events sent to the Syndicator's session which do not have a
286 handler will go to the Syndicator's "_default" handler, will generate
287 "USER events" of the same name. If you install your own "_default"
288 handler, make sure you do the same thing before you handle an event:
289
290 use Object::Pluggable::Constants 'PLUGIN_EAT_ALL';
291
292 $poe_kernel->state('_default', $self, '__default');
293
294 sub __default {
295 my ($self, $event, $args) = @_[OBJECT, ARG0, ARG1];
296
297 # do nothing if a plugin eats the event
298 return if $self->send_user_event($event, [@$args]) == PLUGIN_EAT_ALL;
299
300 # handle the event
301 # ...
302 }
303
304 Note that the handler for the "_default" event must be named something
305 other than '_default', because that name is reserved for the plugin-type
306 default handler (see the Object::Pluggable docs).
307
308 Output events
309 The Syndicator will send the following events at various times. The
310 'syndicator_' prefix in these event names can be customized with a
311 'prefix' argument to "_syndicator_init" in "_syndicator_init".
312
313 "syndicator_registered"
314 Sent once to the requesting session on registration (see "register").
315 "ARG0" is a reference to the component's object.
316
317 "syndicator_shutdown"
318 Sent to all interested sessions when the component has been shut down.
319 See "_syndicator_destroy".
320
321 "syndicator_delay_set"
322 Sent to the subclass, plugins, and all interested sessions on a
323 successful addition of a delayed event using the "delay" method. "ARG0"
324 will be the alarm_id which can be used later with "delay_remove".
325 Subsequent parameters are the arguments that were passed to "delay".
326
327 "syndicator_delay_removed"
328 Sent to the subclass, plugins, and all interested sessions when a
329 delayed event is successfully removed. "ARG0" will be the alarm_id that
330 was removed. Subsequent parameters are the arguments that were passed to
331 "delay".
332
333 All other events
334 All other events sent by the Syndicator are USER events (generated with
335 "send_user_event") and SERVER events (generated with "send_event*")
336 which will be delivered normally. Your subclass and plugins are
337 responsible for generating them.
338
339SIGNALS
340 The component will handle a number of custom signals that you may send
341 using POE::Kernel's "signal" method. They allow any session to
342 communicate with every instance of the component in certain ways without
343 having references to their objects or knowing about their sessions. The
344 names of these signals can be customized with "_syndicator_init".
345
346 "SYNDICATOR_REGISTER"
347 Registers for an event with the component. See "register".
348
349 "SYNDICATOR_SHUTDOWN"
350 Causes a 'shutdown' event to be sent to your session. Any arguments to
351 the signal will be passed along to the event. That's where you should
352 clean up and call "_syndicator_destroy".
353
354AUTHOR
355 Hinrik Örn Sigurðsson, hinrik.sig@gmail.com, Chris "BinGOs" Williams
356 chris@bingosnet.co.uk, Apocalypse apocal@cpan.org, and probably others.
357
358LICENSE AND COPYRIGHT
359 Copyright 2011 Hinrik Örn Sigurðsson
360
361 This program is free software, you can redistribute it and/or modify it
362 under the same terms as Perl itself.
363
364