# NAME

MooX::Role::POE::Emitter - Pluggable POE event emitter role for cows

# SYNOPSIS

   ## A POE::Session that can broadcast events to listeners:
   package My::EventEmitter;
   use POE;
   use Moo;
   with 'MooX::Role::POE::Emitter';

   sub spawn {
     my ($self, %args) = @_;

     $self->set_object_states(
       [
         $self => {
           ## Add some extra handlers to our Emitter:
           'emitter_started' => '_emitter_started',
           'emitter_stopped' => '_emitter_stopped',
         },

         ## Include any object_states we had previously
         ## (e.g. states added at construction time):
         (
           $self->has_object_states ?
             @{ $self->object_states } : ()
         ),

         ## Maybe include from named arguments, for example:
         (
           ref $args{object_states} eq 'ARRAY' ?
             @{ $args{object_states} } : ()
         ),
       ],
     );

     ## Start our Emitter's POE::Session:
     $self->_start_emitter;
   }

   sub shutdown {
     my ($self) = @_;
     ## .. do some cleanup, whatever ..
     $self->_shutdown_emitter;
   }

   sub _emitter_started {
     my ($kernel, $self) = @_[KERNEL, OBJECT];
     ## A POE state called when the emitter's session starts.
     ## (Analogous to a normal '_start' handler)
     ## Could load plugins, do initialization, etc.
   }

   sub _emitter_stopped {
     ## Opposite of 'emitter_started'
   }

   sub do_something {
     my ($self, @things) = @_;
     # ... do some work ...
     # ... emit an event:
     $self->emit( did_stuff => @things )
   }

   ## A listening POE::Session:
   package My::Listener;
   use POE;

   sub spawn {
     # This spawn() takes an alias/session to subscribe to:
     my ($self, $alias_or_sessionID) = @_;

     POE::Session->create(
       ## Set up a Session, etc
       object_states => [
         $self => [
             'emitted_did_stuff',
             # ...
         ],
       ],
     );

     ## Subscribe to all events from $alias_or_sessionID:
     $poe_kernel->call(
       $alias_or_sessionID => subscribe => 'all'
     );
   }

   sub emitted_did_stuff {
     my ($kernel, $self) = @_[KERNEL, OBJECT];
     ## Received 'did_stuff' from Emitter
     my @things = @_[ARG0 .. $#_];
     # ...
   }

# DESCRIPTION

Consuming this [Moo::Role](https://metacpan.org/pod/Moo::Role) gives your class a [POE::Session](https://metacpan.org/pod/POE::Session) capable of
processing events via loaded plugins and/or emitting them to registered
"listener" sessions.

It is derived from [POE::Component::Syndicator](https://metacpan.org/pod/POE::Component::Syndicator) by BINGOS, HINRIK, APOCAL
et al, but with more cows ;-) and a few extra features (such as anonymous
coderef callbacks; see ["yield"](#yield)), as well as the
faster plugin dispatch system that comes with [MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable).

The Emitter role consumes [MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable),
making your emitter pluggable (see the
[MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable) documentation for plugin-related details).

You do not need to create your own [POE::Session](https://metacpan.org/pod/POE::Session); calling
["\_start\_emitter"](#_start_emitter) will spawn one for you.

You also get some useful sugar over POE event dispatch; see ["Methods"](#methods).

## Creating an Emitter

["SYNOPSIS"](#synopsis) contains an emitter that uses **set\_$attrib** methods to
configure itself when `spawn()` is called; attributes can, of course,
be set when your Emitter is constructed:

   my $emitter = MyEmitter->new(
     alias => 'my_emitter',
     pluggable_type_prefixes => {
       NOTIFY  => 'Notify',
       PROCESS => 'Proc',
     },
     # . . .
   );

### Attributes

Most of these can be altered via **set\_$attrib** methods at any time before
["\_start\_emitter"](#_start_emitter) is called. Changing an emitter's configuration after it has
been started may result in undesirable behavior ;-)

Public attributes provide **has\_** prefixed predicates; e.g.
**has\_event\_prefix**.

#### alias

**alias** specifies the POE::Kernel alias used for our [POE::Session](https://metacpan.org/pod/POE::Session);
defaults to the stringified object.

Set via **set\_alias**. If the emitter is running, a prefixed **alias\_set**
event is emitted to notify listeners that need to know where to reach the emitter.

#### event\_prefix

**event\_prefix** is prepended to notification events before they are
dispatched to listening sessions. It is also used for the plugin
pipeline's internal events; see ["\_pluggable\_event" in MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable#pluggable_event)
for details.

Defaults to `emitted_`

Set via **set\_event\_prefix**

#### pluggable\_type\_prefixes

**pluggable\_type\_prefixes** is a hash reference that can optionally be set
to change the default [MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable) plugin handler prefixes for
`PROCESS` and `NOTIFY` (which default to `P` and `N`, respectively):

   my $emitter = $class->new(
     pluggable_type_prefixes => {
       PROCESS => 'P',
       NOTIFY  => 'N',
     },
   );

Set via **set\_pluggable\_type\_prefixes**

#### object\_states

**object\_states** is an array reference suitable for passing to
[POE::Session](https://metacpan.org/pod/POE::Session); the subclasses own handlers should be added to
**object\_states** prior to calling ["\_start\_emitter"](#_start_emitter).

Set via **set\_object\_states**

#### register\_prefix

**register\_prefix** is prepended to 'register' and 'unregister' methods
called on plugins at load time (see [MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable)).

Defaults to _Emitter\__

Set via **set\_register\_prefix**

#### session\_id

**session\_id** is our emitter's [POE::Session](https://metacpan.org/pod/POE::Session) ID, set when our Session is
started via ["\_start\_emitter"](#_start_emitter).

#### shutdown\_signal

**shutdown\_signal** is the name of the [POE](https://metacpan.org/pod/POE) signal that will trigger a
shutdown (used to shut down multiple Emitters). See ["Signals"](#signals)

### \_start\_emitter

**\_start\_emitter()** should be called on our object to spawn the actual
[POE::Session](https://metacpan.org/pod/POE::Session). It takes no arguments and should be called after the
object has been configured.

### \_shutdown\_emitter

**\_shutdown\_emitter()** must be called to terminate the Emitter's
[POE::Session](https://metacpan.org/pod/POE::Session)

A 'shutdown' event will be emitted before sessions are dropped.

## Listening sessions

### Session event subscription

An external [POE::Session](https://metacpan.org/pod/POE::Session) can subscribe to receive events via
normal POE event dispatch by sending a `subscribe`:

   $poe_kernel->post( $emitter->session_id,
     'subscribe',
     @events
   );

Listening sessions are consumers; they cannot modify event arguments in
any meaningful way, and will receive arguments as-normal (in @\_\[ARG0 ..
$#\_\] like any other POE state). Plugins operate differently and receive
references to arguments that can be modified -- see
[MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable) for details.

### Session event unregistration

An external Session can unregister subscribed events using the same syntax
as above:

   $poe_kernel->post( $emitter->session_id,
     'unsubscribe',
     @events
   );

If no events are specified, then any previously subscribed events are
unregistered.

Note that unsubscribing from 'all' does not carry the same behavior; that
is to say, a subscriber can subscribe/unsubscribe for 'all' separately from
some set of specifically named events.

## Receiving events

### Events delivered to listeners

Events are delivered to subscribed listener sessions as normal POE events,
with the configured ["event\_prefix"](#event_prefix) prepended and arguments available via
` @_[ARG0 .. $#_] ` as normal.

   sub emitted_my_event {
     my ($kernel, $self) = @_[KERNEL, OBJECT];
     my @args = @_[ARG0 .. $#_];
     # . . .
   }

See ["Session event subscription"](#session-event-subscription) and ["emit"](#emit)

### Events delivered to this session

The emitter's [POE::Session](https://metacpan.org/pod/POE::Session) provides a '\_default' handler that
redispatches unknown POE-delivered events to ["process"](#process)
(except for events prefixed with '\_', which are reserved).

You can change this behavior by overriding '\_emitter\_default' -- here's a
direct adaption of the example from [POE::Component::Syndicator](https://metacpan.org/pod/POE::Component::Syndicator):

   use Moo;
   use POE;
   with 'MooX::Role::POE::Emitter';
   around '_emitter_default' => sub {
     my $orig = shift;
     my ($kernel, $self) = @_[KERNEL, OBJECT];
     my ($event, $args)  = @_[ARG0, ARG1];

     ## process(), then do something else, for example
     return if $self->process( $event, @$args ) == EAT_ALL;

     . . .
   };

(Note that due to internal redispatch $\_\[SENDER\] will be the Emitter's
Session.)

## EAT values

[MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable) uses `EAT_*` constants to indicate event
lifetime.

If a plugin in the pipeline returns EAT\_CLIENT or EAT\_ALL, events
are not dispatched to subscribed listening sessions; a dispatched NOTIFY
event goes to your emitter's Session if it is subscribed to receive it,
then to the plugin pipeline, and finally to other subscribed listener
Sessions **unless** a plugin returned EAT\_CLIENT or EAT\_ALL.

See ["emit"](#emit) for more on dispatch behavior and event lifetime. See
[MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable) for details regarding plugins.

### NOTIFY events

**NOTIFY** events are intended to be dispatched asynchronously to our own
session, any loaded plugins in the pipeline, and subscribed listening
sessions, respectively.

See ["emit"](#emit).

### PROCESS events

**PROCESS** events are intended to be processed by the plugin pipeline
immediately; these are intended for message processing and similar
synchronous action handled by plugins.

Handlers for **PROCESS** events are prefixed with `P_`

See ["process"](#process).

## Sending events

### emit

   $self->emit( $event, @args );

**emit()** dispatches ["NOTIFY events"](#notify-events) -- these events are dispatched
first to our own session (with ["event\_prefix"](#event_prefix) prepended), then any
loaded plugins in the pipeline (with `N_` prepended), then registered
sessions (with ["event\_prefix"](#event_prefix) prepended):

   ## With default event_prefix:
   $self->emit( 'my_event', @args )
   #  -> Dispatched to own session as 'emitted_my_event'
   #  -> Dispatched to plugin pipeline as 'N_my_event'
   #  -> Dispatched to registered sessions as 'emitted_my_event'
   #     *unless* a plugin returned EAT_CLIENT or EAT_ALL

See ["Receiving events"](#receiving-events), ["EAT values"](#eat-values)

### emit\_now

   $self->emit_now( $event, @args );

**emit\_now()** synchronously dispatches ["NOTIFY events"](#notify-events) -- see
["emit"](#emit).

### process

   $self->process( $event, @args );

**process()** calls registered plugin handlers for ["PROCESS events"](#process-events)
immediately; these are **not** dispatched to listening sessions.

Returns the same value as ["\_pluggable\_process" in MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable#pluggable_process).

See [MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable) for details on pluggable
event dispatch.

## Methods

These methods provide easy proxy mechanisms for issuing POE events and
managing timers within the context of the emitter's [POE::Session](https://metacpan.org/pod/POE::Session).

### yield

   $self->yield( $poe_event, @args );

Provides an interface to [POE::Kernel](https://metacpan.org/pod/POE::Kernel)'s yield/post() method, dispatching
POE events within the context of the emitter's session.

The event can be either a named event/state dispatched to your Emitter's
[POE::Session](https://metacpan.org/pod/POE::Session):

   $emitter->yield( 'some_event', @args );

.. or an anonymous coderef, which is executed as if it were a named
POE state belonging to your Emitter:

   $emitter->yield( sub {
     ## $_[OBJECT] is the Emitter's object:
     my ($kernel, $self) = @_[KERNEL, OBJECT];
     my @params          = @_[ARG0 .. $#_];

     ## $_[STATE] is the current coderef
     ## Yield ourselves again, for example:
     $self->yield( $_[STATE], @new_args )
       if $some_condition;
   }, $some, $args );

Inside an anonymous coderef callback such as shown above, `$_[OBJECT]` is
the Emitter's `$self` object and `$_[STATE]` contains the callback
coderef itself.

### call

   $self->call( $poe_event, @args );

The synchronous counterpart to ["yield"](#yield).

### timer

   my $alarm_id = $self->timer(
     $delayed_seconds,
     $event,
     @args
   );

Set a timer in the context of the emitter's [POE::Session](https://metacpan.org/pod/POE::Session). Returns the
POE alarm ID.

The event can be either a named event/state or an anonymous coderef (see
["yield"](#yield)).

A prefixed (["event\_prefix"](#event_prefix)) 'timer\_set' event is emitted when a timer is
set. Arguments are the alarm ID, the event name or coderef, the delay time,
and any event parameters, respectively.

### timer\_del

   $self->timer_del( $alarm_id );

Clears a pending ["timer"](#timer).

A prefixed (["event\_prefix"](#event_prefix)) 'timer\_deleted' event is emitted when a timer
is deleted. Arguments are the removed alarm ID, the event name or coderef,
and any event parameters, respectively.

## Signals

### Shutdown Signal

The attribute ["shutdown\_signal"](#shutdown_signal) defines a POE signal that will trigger a
shutdown; it defaults to `SHUTDOWN_EMITTER`:

   ## Shutdown *all* emitters (with a default shutdown_signal()):
   $poe_kernel->signal( $poe_kernel, 'SHUTDOWN_EMITTER' );

See ["Signal Watcher Methods" in POE::Kernel](https://metacpan.org/pod/POE::Kernel#Signal-Watcher-Methods) for details on [POE](https://metacpan.org/pod/POE) signals.

# SEE ALSO

For details regarding POE, see [POE](https://metacpan.org/pod/POE), [POE::Kernel](https://metacpan.org/pod/POE::Kernel), [POE::Session](https://metacpan.org/pod/POE::Session)

For details regarding Moo classes and Roles, see [Moo](https://metacpan.org/pod/Moo), [Moo::Role](https://metacpan.org/pod/Moo::Role),
[Role::Tiny](https://metacpan.org/pod/Role::Tiny)

# AUTHOR

Jon Portnoy <[email protected]>

Written from the ground up, but conceptually derived from
[POE::Component::Syndicator](https://metacpan.org/pod/POE::Component::Syndicator)-0.06 copyright Hinrik Orn Sigurosson (HINRIK),
Chris Williams (BINGOS), APOCAL et al -- that will probably do you for
non-Moo(se) use cases; I needed something cow-like that worked with
[MooX::Role::Pluggable](https://metacpan.org/pod/MooX::Role::Pluggable).

Licensed under the same terms as Perl 5; see the license that came with your
Perl distribution for details.