Sponsoring The Perl Toolchain Summit 2025: Help make this important event another success Learn more

# Declare our package
# Standard stuff to catch errors
use strict qw(subs vars refs); # Make sure we can't mess up
use warnings FATAL => 'all'; # Enable warnings to catch errors
# Initialize our version
our $VERSION = '0.' . sprintf( "%04d", (qw($Revision: 1050 $))[1] );
# Import what we need
use Carp qw( croak );
# Load the constants
use POE::Component::Lightspeed::Constants qw( ACTION_INTROSPECTION FROM_KERNEL FROM_SESSION FROM_STATE FROM_FILE FROM_LINE DEST_KERNEL DEST_SESSION );
# Make sure the router instance is loaded no matter what
# Spawn the Router session to make sure :)
POE::Component::Lightspeed::Router->spawn();
# We export some stuff
require Exporter;
our @ISA = qw( Exporter );
our @EXPORT_OK = qw( list_kernels list_sessions list_states );
# Lists all kernels
sub list_kernels {
# Get the heap from the router session
my $heap = $POE::Kernel::poe_kernel->_resolve_session( $POE::Component::Lightspeed::Router::SES_ALIAS )->get_heap();
# Get the list of kernels
my @kernels = $heap->{'GRAPH'}->vertices();
# Return it!
return \@kernels;
}
# Lists all sessions in kernel X
sub list_sessions {
my( $dest, $rsvp ) = @_;
# Validate the kernel
if ( ! defined $dest ) {
return undef;
} elsif ( ref( $dest ) ) {
if ( ref( $dest ) eq 'POE::Component::Lightspeed::Hack::Session' ) {
# Cool! Convert it :)
$dest = $dest->remote_kernel();
} elsif ( ref( $dest ) ne 'ARRAY' ) {
return undef;
}
}
# Validate the RSVP
$rsvp = POE::Component::Lightspeed::Router::ValidateDestination( $rsvp );
if ( ! defined $rsvp ) {
return undef;
}
# Get the heap from the router session
my $heap = $POE::Kernel::poe_kernel->_resolve_session( $POE::Component::Lightspeed::Router::SES_ALIAS )->get_heap();
# Get the session alias
my @list = $POE::Kernel::poe_kernel->alias_list( $POE::Kernel::poe_kernel->get_active_session() );
if ( ! defined $list[0] ) {
$list[0] = $POE::Kernel::poe_kernel->get_active_session()->ID;
}
# Construct the from array
my $from = [];
$from->[ FROM_KERNEL ] = $heap->{'MYKERNEL'};
# Add the session
$from->[ FROM_SESSION ] = $list[0];
# Add the state
$from->[ FROM_STATE ] = $POE::Kernel::poe_kernel->get_active_event();
# Add the file/line
push( @$from, (caller)[1,2] );
# Is it a local introspection request?
if ( $dest eq $heap->{'MYKERNEL'} or $dest eq '*' ) {
# Send it to the router to emulate a "packet"
$POE::Kernel::poe_kernel->post(
$POE::Component::Lightspeed::Router::SES_ALIAS,
'ACTION_' . ACTION_INTROSPECTION,
[
$heap->{'MYKERNEL'}, # MSG_TO
$heap->{'MYKERNEL'}, # MSG_FROM
ACTION_INTROSPECTION, # MSG_ACTION
[ # MSG_DATA
'SESSION', # INTROSPECTION_WHAT
$from, # INTROSPECTION_FROM
$rsvp, # INTROSPECTION_RSVP
],
],
);
}
# Send it off!
if ( $dest ne $heap->{'MYKERNEL'} ) {
POE::Component::Lightspeed::Router::SendMessage( $heap, [
$dest, # MSG_TO
undef, # MSG_FROM
ACTION_INTROSPECTION, # MSG_ACTION
[ # MSG_DATA
'SESSION', # INTROSPECTION_WHAT
$from, # INTROSPECTION_FROM
$rsvp, # INTROSPECTION_RSVP
],
] );
}
# All done!
return 1;
}
# Lists all states in session X in kernel Y
sub list_states {
my( $dest, $rsvp ) = @_;
# Validate the destination
if ( ! defined $dest ) {
return undef;
} elsif ( ! ref( $dest ) ) {
# Okay, before we send it to ValidateDestination, we have to make sure there's a '/' at the end to make it happy
if ( $dest =~ m|^poe://(?:[^/]+)/(?:[^/]+)$| ) {
$dest .= '/';
}
# If it's terribly corrupt, who cares, ValidateDestination will catch it for us :)
$dest = POE::Component::Lightspeed::Router::ValidateDestination( $dest );
if ( ! defined $dest ) {
return undef;
}
} elsif ( ref( $dest ) eq 'ARRAY' ) {
# Must have 2 parts
if ( scalar( @$dest ) != 2 ) {
return undef;
}
} elsif ( ref( $dest ) eq 'HASH' ) {
# Must have 2 parts
if ( ! exists $dest->{'KERNEL'} or ! exists $dest->{'SESSION'} ) {
return undef;
} else {
# Change it into an array
$dest = [ $dest->{'KERNEL'}, $dest->{'SESSION'} ];
}
} elsif ( ref( $dest ) eq 'POE::Component::Lightspeed::Hack::Session' ) {
# Cool! Convert it :)
$dest = [ $dest->remote_kernel(), $dest->remote_session() ];
} else {
# What the hell is it?
return undef;
}
# Validate the rsvp
$rsvp = POE::Component::Lightspeed::Router::ValidateDestination( $rsvp );
if ( ! defined $rsvp ) {
return undef;
}
# Get the heap from the router session
my $heap = $POE::Kernel::poe_kernel->_resolve_session( $POE::Component::Lightspeed::Router::SES_ALIAS )->get_heap();
# Construct the from array
my $from = [];
$from->[ FROM_KERNEL ] = $heap->{'MYKERNEL'};
# Add the session
my @list = $POE::Kernel::poe_kernel->alias_list( $POE::Kernel::poe_kernel->get_active_session() );
if ( ! defined $list[0] ) {
$list[0] = $POE::Kernel::poe_kernel->get_active_session()->ID;
}
$from->[ FROM_SESSION ] = $list[0];
# Add the state
$from->[ FROM_STATE ] = $POE::Kernel::poe_kernel->get_active_event();
# Add the file/line
push( @$from, (caller)[1,2] );
# Is it a local introspection request?
if ( POE::Component::Lightspeed::Router::FindOurself( $heap->{'MYKERNEL'}, $dest->[ DEST_KERNEL ] ) ) {
# Send it to the router to emulate a "packet"
$POE::Kernel::poe_kernel->post(
$POE::Component::Lightspeed::Router::SES_ALIAS,
'ACTION_' . ACTION_INTROSPECTION,
[
$heap->{'MYKERNEL'}, # MSG_TO
$heap->{'MYKERNEL'}, # MSG_FROM
ACTION_INTROSPECTION, # MSG_ACTION
[ # MSG_DATA
'STATE', # INTROSPECTION_WHAT
$from, # INTROSPECTION_FROM
$rsvp, # INTROSPECTION_RSVP
$dest->[ DEST_SESSION ], # INTROSPECTION_ARGS
],
],
);
}
# Send it off!
POE::Component::Lightspeed::Router::SendMessage( $heap, [
$dest->[ DEST_KERNEL ], # MSG_TO
undef, # MSG_FROM
ACTION_INTROSPECTION, # MSG_ACTION
[ # MSG_DATA
'STATE', # INTROSPECTION_WHAT
$from, # INTROSPECTION_FROM
$rsvp, # INTROSPECTION_RSVP
$dest->[ DEST_SESSION ], # INTROSPECTION_ARGS
],
] );
# All done!
return 1;
}
# End of module
1;
__END__
=head1 NAME
POE::Component::Lightspeed::Introspection - Discovering your network!
=head1 SYNOPSIS
use POE;
use POE::Component::Lightspeed::Client;
use POE::Component::Lightspeed::Server;
use POE::Component::Lightspeed::Introspection qw( list_kernels list_sessions list_states );
# Spawn your client/server session here and connect to the network
# Find out the kernels in the network
my $kernels = list_kernels();
print "Kernels:", join( " ,", @$kernels );
# Query a specific kernel for it's sessions
# Remember, we need a RSVP specifier here
list_sessions( 'kernel1', 'poe://mykernel/mysession/got_sessions' );
# This rsvp will get 2 events, one from each kernel it queried
list_sessions( [ qw( kernel1 kernel2 ) ], 'poe://mykernel/mysession/got_sessions' );
# Inside an event handler where $_[SENDER] is a remote kernel
list_sessions( $_[SENDER], 'poe://mykernel/mysession/got_sessions' );
# Query a specific kernel / session for it's states
# Basically, this accepts the full destination specifier, only without the state parameter
# This is also allowed
list_states( [ [ qw( kernel1 kernel2 ) ], 'mysession' ], 'poe://mykernel/mysession/got_states' );
# Madness, madness!
list_states( { 'KERNEL' => '*', 'SESSION' => '*' }, 'poe://mykernel/mysession/got_states' );
# Inside an event handler where $_[SENDER] is a remote kernel
list_states( $_[SENDER], 'poe://mykernel/mysession/got_states' );
=head1 ABSTRACT
This module presents an easy API for finding information about the network.
=head1 CHANGES
=head2 0.03
- Initial version
=head1 DESCRIPTION
All you need to do is import the 3 subroutines provided.
=head1 METHODS
=head2 list_kernels
Requires no arguments
Returns an arrayref of kernel names
=head2 list_sessions
Requires two arguments
- The kernel name to query
Can be a scalar with the kernel name, or '*'
Can be an arrayref full of kernel names
Can be $_[SENDER] when it's a remote kernel
- The RSVP to send the results
Must be a fully-qualified destination specifier as explained in the Lightspeed docs
NOTE: This will return every alias a session has, not only the first alias!
Returns nothing, the data will be sent to the RSVP
ARG0 = kernel name
ARG1 = arrayref of sessions
Example:
[
[ 'mysession',
'secondalias',
'thirdalias',
],
[ 'weeble',
],
[ 'frobnicate',
]
]
=head2 list_states
Requires two arguments
- The kernel/session to query
Can be a fully-qualified destination specifier without the state, i.e. 'poe://kernel/session'
Can be an arrayref as explained in the Lightspeed docs, without the 3rd element set
Can be a hashref with the KERNEL and SESSION keys
Can be $_[SENDER] when it's a remote kernel
- The RSVP to send the results
Must be a fully-qualified destination specifier as explained in the Lightspeed docs
NOTE: This will return only one alias per session, to avoid confusion over duplicate aliases
Returns nothing, the data will be sent to the RSVP
ARG0 = kernel name
ARG1 = hashref of sessions -> array of states
Example:
{
'mysession' => [ '_stop',
'_default',
'mystate',
'mystate2',
],
'othersession' => [ 'floo',
'bar',
]
}
=head1 EXPORT
Exports the 3 subs in EXPORT_OK
=head1 SEE ALSO
L<POE::Component::Lightspeed>
=head1 AUTHOR
Apocalypse E<lt>apocal@cpan.orgE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright 2005 by Apocalypse
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut