—# Declare our package
# Standard stuff to catch errors
# Initialize our version
our
$VERSION
=
'0.'
.
sprintf
(
"%04d"
, (
qw($Revision: 1050 $)
)[1] );
# Import what we need
# 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
$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
list_states( 'poe://kernel1/mysession', 'poe://mykernel/mysession/got_states' );
# 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