NAME
Net::Object::Peer - Peer-to-Peer Publish/Subscribe Network of Objects
VERSION
version 0.06
SYNOPSIS
use 5.10.0;
package Node;
use Moo;
with 'Net::Object::Peer';
has name => is => ( 'ro', required => 1 );
sub default_events { qw[ hey ] }
sub _notify_subscribed {
my ( $self, $peer, $name ) = @_;
say $self->name, ":\t@{[ $peer->name ]} subscribed to event $name";
}
sub _cb_hey {
my ( $self, $event ) = @_;
say $self->name,
":\t@{[ $event->emitter->name ]} sent @{[$event->name]}";
}
sub _cb_unsubscribed {
my ( $self, $event ) = @_;
say $self->name, ":\t@{[ $event->emitter->name ]} unsubscribed";
}
package main;
my $n1 = Node->new( name => 'N1' );
my $n2 = Node->new( name => 'N2' );
my $n3 = Node->new( name => 'N3' );
# Net::Object::Peer provides an "unsubscribed" event; $n1 will be
# notified when $n2 unsubscribes from it
$n1->subscribe( $n2, 'unsubscribed' );
# $n2 and $n3 will be notified when $n1 sends a "hey" event, and $n1
# will be notified that they have subscribed
$n2->subscribe( $n1, 'hey' );
$n3->subscribe( $n1, 'hey' );
# both $n2 and $n3 will get notified
$n1->emit( 'hey' );
# only $n2 gets notified
$n1->send( $n2, 'hey' );
# destroy $n2; $n2 will unsubscribe from all of its events and $n1
# will be notified that $n2 has unsubscribed from it.
undef $n2;
Resulting in:
N2: N1 subscribed to event unsubscribed
N1: N2 subscribed to event hey
N1: N3 subscribed to event hey
N2: N1 sent hey
N3: N1 sent hey
N2: N1 sent hey
N1: N2 unsubscribed
DESCRIPTION
Net::Object::Peer is a Moo Role which implements a publish/subscribe peer-to-peer messaging system, based upon Beam::Emitter. Objects in the network may broadcast events to all subscribers or may send events to a particular subscriber.
Subscriptions and unsubscriptions are tracked and messages will be sent to affected objects upon request.
While Net::Object::Peer is designed around the concept of nodes being objects with methods as event handlers, it retains Beam::Emitter's ability to register code references as well.
Net::Object::Peer::Cookbook provides some recipes.
Usage
As Net::Object::Peer is purely peer based with no common message bus, a network is built up by creating a set of network nodes and linking them via subscriptions.
my $n1 = Node->new( name => 'N1' );
my $n2 = Node->new( name => 'N2' );
$n1->subscribe( $n2, 'changed' );
Here $n1
subscribes to $n2
's changed
event. By default, $n1
's _cb_changed
method is invoked when $n2
emits a changed
event.
Events
An emitter must register the events that it will emit. Here's how
Class defaults
A default set of events for the class may be specified by defining the "default_events" class method, which should return a list of event names:
sub default_events{ qw[ evt1 evt2 evt3 ] }
Object defaults
During object construction, the events attribute may be used to specify a list of events.
Runtime manipulation
The "events" object method may be used to overwrite the list of events.
When a subscriber recieves an event, its registered handler for that event type is invoked. If the object creating the event used the "emit" or "send" methods,
$emitter->emit( $event_name );
the event handler will be invoked as
$subscriber->method( $event );
where $event
is an object derived from the Net::Object::Peer::Event class. (This assumes that the handler is a method; it may be a simple callback).
If the event was created with the "emit_args" or "send_args" methods,
$emitter->emit_args( $event_name, @arguments );
the event handler will invoked as
$subscriber->method( @arguments );
Subscription and Unsubscription Events
When a subscriber registers one or more event handlers with an emitter via the subscriber's "subscribe" method, the emitter's _notify_subscribed
method will be invoked (if it exists) as
$emitter->_notify_subscribed( $subscriber, @event_names );
If the subscription already exists, it will be unsubscribed and then resubscribed.
After a subscriber de-registers a handler, either explicitly via "unsubscribe" or when the object is destroyed, it will "emit" an unsubscribed
event with a Net::Object::Peer::UnsubscribeEvent object as a payload.
While emitters are not automatically subscribed to unsubscribed
events, this is easily accomplished by adding code to the emitters' _notify_subscribed
method.
Detach Events
When an object is destroyed, it emits a detach
event after unsubscribing from other peers' events.
ATTRIBUTES
event_handler_prefix
The string which prefixes default event handler method names. See "subscribe". It will by default be initialized to the return value of the "default_event_handler_prefix" method. It may be specified during object construction.
For example, the default handler method name for an event named changed
would be _cb_changed
. The class must provide that method. See "subscribe" for more information.
addr
A Net::Object::Peer::RefAddr object providing a unique identity for this emitter.
METHODS
emits_events
$bool = $obj->emits_events( @event_names );
Returns true if the object emits all of the named events
default_events
@events = $class->default_events;
Returns a list of events which this class will emit, excluding the detach
and unsubscribed
events. The default implementation returns an empty list. A per object event list may be specified via the "events" attribute or the events
option to the constructor.
new
$obj = Net::Object::Peer->new( %args | \%args );
Construct a new object. The following arguments are available:
- event_handler_prefix => string
-
The string which prefixes default event handler method names. See "event_handler_prefix"
- events => string | arrayref
-
The name(s) of the event(s) this object will emit (don't include the
unsubscribed
anddetach
events). May be a single string or an arrayref. If not specified, the list of events will be initialized via the "default_events" class method.
default_event_handler_prefix
This class method returns the prefix for the default event handler method names. It defaults to returning _cb_
.
build_sub
$coderef = $self->build_sub( $emitter, @tuple );
build_sub
is the method responsible for creating and compiling the code for an event handler. It is invoked from the "subscribe()" method, with the following parameters
$emitter
-
The emitter object.
@tuple
-
the tuple passed to "subscribe" for this event.
The default implementation will return a Sub::Quote::quote_sub generated code reference for method calls and code specified as a string. See "Loop Detecton" in Net::Object::Peer::Cookbook for an example of using this attribute to inline additional code in the event handler.
subscribe
$self->subscribe( $peer, @event_tuple [, @event_tuple, ... ] );
Subscribe to one or more events sent by $peer
, which must consume the Net::Object::Peer role. If $peer
additionally consumes the Net::Object::Peer::Ephemeral role, a strong reference to $peer
is stored. (See "Translation/Proxy Nodes" in Net::Object::Peer::Cookbook.) An attempt to subscribe to an event the peer does not produce will throw an exception.
The event name and the action to be performed when the event is emitted are specified by a tuple with the following forms:
$event_name
-
the event handler will invoke the
${prefix}${event_name}
method on$self
, where$prefix
is the event_handler_prefix attribute. $event_name => { method => $method_name }
-
The event handler will invoke the
$method_name
method on$self
. $event_name => CODEREF
-
The passed code reference is called.
$event_name => { code => $code, capture => \%capture }
-
$code
is a string containing code to be run by the event handler.%capture
is a hash containing variable captures. See the documentation for "\%captures" in "quote_sub" in Sub::Quote for more information.
If $peer
provides a _notify_subscribed
method, that will be invoked as
$peer->_notify_subscribed( $self, $event_name, ... );
for each subscription.
unsubscribe
# Unsubscribe from all events from all peers.
$self->unsubscribe;
# Unsubscribe from all events emitted by a peer
$self->unsubscribe( $peer );
# Unsubscribe from one or more events emitted by a peer
$self->unsubscribe( $peer, $event_name [, $event_name [, ... ]);
# Unsubscribe from the peer and event specified by the passed
# Net::Object::Peer::Event object
$self->unsubscribe( $event_object );
# Unsubscribe from one or more events emitted by all peers
$self->unsubscribe( $event_name [, $event_name [, ... ] ] )
Unsubscribe from events/peers. After unsubscription, an unsubscribed event with a Net::Object::Peer::UnsubscribeEvent as a payload will be sent to affected peers who have subscribed to the unsubscribed event(s).
$peer
may be either a Net::Object::Peer or a Net::Object::Peer::RefAddr object.
Note that Net::Object::Peer::Event objects which are passed to event handlers may have a masqueraded emitter
attribute. Attempting to unsubscribe from that emitter
is unwise. Instead, pass either the event object or the addr
field in that object, which is guaranteed to identify the actual emitter subscribed to.
events
@events = $obj->events;
$obj->events( \@event_names | $event_name );
As a getter, returns a list of event names which the object may emit.
As a setter, accepts either an arrayref or a single event name. Event names must a valid Perl identifier (e.g., no :
or -
characters).
detach
$self->detach;
Detach the object from the network. It will
Unsubscribe from all events from all peers.
Emit an
unsubscribed
event with a Net::Object::Peer::UnsubscribeEvent as a payload.Emit a
detach
event.
subscriptions
# return all subscriptions
my @subscriptions = $self->subscriptions;
# return matching subscriptions
my @subscriptions = $self->subscriptions( $coderef | %spec );
Returns the events to which $self
is subscribed as a list of hashrefs (see Net::Object::Peer::Subscription::as_hashref). If arguments are specified, only those which match are returned; see "find" in Net::Object::Peer::Subscrition;
emit
$self->emit( $event_name, %args );
Broadcast the named event to all subscribed peers. %args
contains arguments to be passed the the payload class constructor. The default payload class is a Net::Object::Peer::Event object; use the class
key to specify an alternate class, which must be derived from Net::Object::Peer::Event. An attempt to emit an event which is not supported by the emitter will cause an exception to be thrown.
send
$self->send( $peer, $event_name, %args );
This is similar to the "emit" method, but only sends the event to the specified peer. An attempt to emit an event which is not supported by the emitter will cause an exception to be thrown.
emit_args
$self->emit_args( $event_name, @args );
Broadcast the named event to all subscribed peers. @args
will be passed directly to each subscriber's callback. An attempt to emit an event which is not supported by the emitter will cause an exception to be thrown.
send_args
$self->send_args( $peer, $event_name, @args );
This is similar to the "emit_args" method, but only sends the event to the specified peer. An attempt to emit an event which is not supported by the emitter will cause an exception to be thrown.
AUTHOR
Diab Jerius <djerius@cpan.org>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2016 by Smithsonian Astrophysical Observatory.
This is free software, licensed under:
The GNU General Public License, Version 3, June 2007