NAME

Net::Object::Peer - Peer-to-Peer Publish/Subscribe Network of Objects

VERSION

version 0.04

SYNOPSIS

use 5.10.0;

package Node;
use Moo;
with 'Net::Object::Peer';

has name => is => ( 'ro', required => 1 );

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_unsubscribe {
    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 "unsubscribe" event; $n1 will be
# notified when $n2 unsubscribes from it
$n1->subscribe( $n2, 'unsubscribe' );

# $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 unsubscribe
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

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 unsubscribe event with a Net::Object::Peer::UnsubscribeEvent object as a payload.

While emitters are not automatically subscribed to "unsubscribe" 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

addr

A Net::Object::Peer::RefAddr object providing a unique identity for this emitter.

METHODS

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.)

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 _cb_${event_name} method on $self.

$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 unsubscribe 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.

detach

$self->detach;

Detach the object from the network. It will

  1. Unsubscribe from all events from all peers.

  2. Emit an unsubscribe event with a Net::Object::Peer::UnsubscribeEvent as a payload.

  3. 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.

send

$self->send( $peer, $event_name, %args );

This is similar to the "emit" method, but only sends the event to the specified peer.

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.

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.

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