Provided by: libpoe-component-ikc-perl_0.2402-1_all bug

NAME

       POE::Component::IKC::Responder - POE IKC state handler

SYNOPSIS

           use POE;
           use POE::Component::IKC::Responder;
           create_ikc_responder();
           ...
           $kernel->post('IKC', 'post', $to_state, $state);

           $ikc->publish('my_name', [qw(state1 state2 state3)]);

DESCRIPTION

       This module implements POE IKC state handling.  The responder handles posting states to
       foreign kernels and calling states in the local kernel at the request of foreign kernels.

       There are 2 interfaces to the responder.  Either by sending states to the 'IKC' session or
       the object interface.  While the latter is faster, the better behaved, because POE is a
       cooperative system.

STATES/METHODS

   "spawn"
           POE::Component::IKC::Responder->spawn();

       This function creates the Responder session and object.  Normally,
       POE::Component::IKC::Client or POE::Component::IKC::Server does this for you.  But in some
       applications you want to make sure that the Responder is up and running before then.

   "post"
       Sends an state request to a foreign kernel.  Returns logical true if the state was sent
       and logical false if it was unable to send the request to the foreign kernel.  This does
       not mean that the foreign kernel was able to post the state, however.  Parameters are as
       follows :

       "foreign_state"
         Specifier for the foreign state.   See POE::Component::IKC::Specifier.

       "parameters"
         A reference to anything you want the foreign state to get as ARG0.  If you want to
         specify several parameters, use an array ref and have the foreign state dereference it.

             $kernel->post('IKC', 'post',
                 {kernel=>'Syslog', session=>'logger', state=>'log'},
                 [$faculty, $priority, $message];

         or

             $ikc->post('poe://Syslog/logger/log', [$faculty, $priority, $message]);

         This logs an state with a hypothetical logger.

       See the "PROXY SENDER" below.

   "call"
       This is identical to "post", except it has a 3rd parameter that describes what state
       should receive the return value from the foreign kernel.

           $kernel->post('IKC', 'call',
                       'poe://Pulse/timeserver/time', '',
                       'poe:get_time');

       or

           $ikc->call({kernel=>'Pulse', session=>'timeserver', state=>'time'},
                       '', 'poe://me/get_time');

       This asks the foreign kernel 'Pulse' for the time.  'get_time' state in the current
       session is posted with whatever the foreign state returned.

       You do not have to publish callback messages, because they are temporarily published.  How
       temporary?  They can be posted from a remote kernel ONCE only.  This, of course, is a
       problem because someone else could get in a post before the callback.  Such is life.

       "foreign_state"
          Identical to the "post" "foreign_state" parameter.

       "parameters"
          Identical to the "post" "parameters" parameter.

       "rsvp"
          Event identification for the callback.  That is, this state is called with the return
          value of the foreign state.  Can be a "foreign_state" specifier or simply the name of
          an state in the current session.

           $kernel->call('IKC', 'post',
               {kernel=>'e-comm', session=>'CC', state=>'check'},
               {CC=>$cc, expiry=>$expiry}, folder=>$holder},
               'is_valid');
           # or
           $ikc->call('poe://e-comm/CC/check',
               {CC=>$cc, expiry=>$expiry}, folder=>$holder},
               'poe://me/is_valid');

       This asks the e-comm server to check if a credit card number is "well formed".  Yes, this
       would probably be massive overkill.

       The "rsvp" state does not need to be published.  IKC keeps track of the rsvp state and
       will allow the foreign kernel to post to it.

       See the "PROXY SENDER" below.

   "default"
       Sets the default foreign kernel.  You must be connected to the foreign kernel first.

       Unique parameter is the name of the foreign kernel kernel.

       Returns logical true on success.

   "register"
       Registers foreign kernel names with the responder.  This is done during the negociation
       phase of IKC and is normaly handled by "IKC::Channel".  Will define the default kernel if
       no previous default kernel exists.

       First parameter is either a single kernel name.  Second optional parameter is an array ref
       of kernel aliases to be registered.

   "unregister"
       Unregisters one or more foreign kernel names with the responder.  This is done when the
       foreign kernel disconnects by POE::Component::IKC::Channel.  If this is the default
       kernel, there is no more default kernel.

       First parameter is either a single kernel name or a kernel alias.  Second optional
       parameter is an array ref of kernel aliases to be unregistered.  This second parameter is
       a tad silly, because if you unregister a remote kernel, it goes without saying that all
       it's aliases get unregistered also.

   "register_local"
       Registers new aliases for local kernel with the responder.  This is done internally by
       POE::Component::IKC::Server and POE::Component::IKC::Client. Will NOT define the default
       kernel.

       First and only parameter is an array ref of kernel aliases to be registered.

   "publish"
       Tell IKC that some states in the current session are available for use by foreign
       sessions.

       "session"
         A session alias by which the foreign kernels will call it.  The alias must already have
         been registered with the local kernel.

       "states"
         Arrayref of states that foreign kernels may post.

             $kernel->post('IKC', 'publish', 'me', [qw(foo bar baz)]);
             # or
             $ikc->publish('me', [qw(foo bar baz)]);

   "retract"
       Tell IKC that some states should no longer be available for use by foreign sessions.  You
       do not have to retract all published states.

       "session"
         Same as in "publish"

       "states"
         Same as in "publish".  If not supplied, *all* published states are retracted.

             $kernel->post('IKC', 'retract', 'me', [qw(foo mibble dot)]);
             # or
             $ikc->retract('me', [qw(foo)]);

   "published"
           $list=$kernel->call(IKC=>'published', $session);

       Returns a list of all the published states.

           $hash=$kernel->call(IKC=>'published');

       Returns a hashref, keyed on session IDs.  Values are arrayref of states published by that
       session.

       "session"
         A session alias that you wish the list of states for.

   "subscribe"
       Subscribe to foreign sessions or states.  When you have subscribed to a foreign session, a
       proxy session is created on the local kernel that will allow you to post to it like any
       other local session.

       "specifiers"
          An arrayref of the session or state specifiers you wish to subscribe to.  While the
          wildcard '*' kernel may be used, only the first kernel that acknowledges the
          subscription will be proxied.

       "callback"
          Either a state (for the state interface) or a coderef (for the object interface) that
          is posted (or called) when all subscription requests have either been replied to, or
          have timed out.

          When called, it has a single parameter, an arrayref of all the specifiers that IKC was
          able to subscribe to.  It is up to you to see if you have enough of the foreign
          sessions or states to get the job done, or if you should give up.

          While "callback" isn't required, it makes a lot of sense to use it because it is only
          way to find out when the proxy sessions become available.

          Example :

              $ikc->subscribe([qw(poe://Pulse/timeserver)],
                      sub { $kernel->post('poe://Pulse/timeserver', 'connect') });

          (OK, that's a bad example because we don't check if we actually managed to subscribe or
          not.)

              $kernel->post('IKC', 'subscribe',
                              [qw(poe://e-comm/CC poe://TouchNet/validation
                                  poe://Cantax/JDE poe://Informatrix/JDE)
                              ],
                              'poe:subscribed',
                            );
              # and in state 'subscribed'
              sub subscribed
              {
                  my($kernel, $specs)=@_[KERNEL, ARG0];
                  if(@$specs != 4)
                  {
                      die "Unable to find all the foreign sessions needed";
                  }
                  $kernel->post('poe://Cantax/JDE', 'write', {...somevalues...});
              }

          This is a bit of a mess.  You might want to use the "subscribe" parameter to "spawn"
          instead.

          Subscription receipt timeout is currently set to 120 seconds.

   "unsubscribe"
       Reverse of the "subscribe" method.  However, it is currently not documented well.

   "ping"
       Responds with 'PONG'.  This is auto-published, so it can be called from remote kernels to
       see if the local kernel is still around.  In fact, I don't see any other use for this.

           $kernel->post('poe://remote/IKC', 'ping', 'some_state');
           $kernel->delay('some_state', 60);   # timeout

           sub some_state
           {
               my($pong)=$_[ARG0];
               return if $pong;            # all is cool

               # YOW!  Remote kernel timed out.  RUN AROUND SCREAMING!
           }

   "shutdown"
       Hopefully causes IKC and all peripheral sessions to dissapear in a puff of smoke.  At the
       very least, any sessions left will be either not related to IKC or barely breathing (that
       is, only have aliases keeping them from GC).  This should allow you to sanely shut down
       your process.

   "monitor"
       Allows a session to monitor the state of remote kernels.  Currently, a session is informed
       when a remote kernel is registered, unregistered, subscribed to or unsubscribed from.  One
       should make sure that the IKC alias exists before trying to monitor.  Do this by calling
       POE::Component::IKC::Responder->spawn or in an "on_connect" callback.

           $kernel->post('IKC', 'monitor', $remote_kernel_id, $states);

       $remote_kernel_id
          Name or alias or IKC specifier of the remote kernel you wish to monitor.  You can also
          specify "*" to monitor ALL remote kernels.  If you do, your monitor will be called
          several times for a given kernel.  This is because a kernel has one name and many
          aliases.  For example, a remote kernel will have a unique ID within the local kernel, a
          name (passed to or generated by create_ikc_{kernel,client}) and a globaly unique ID
          assigned by the remote kernel via $kernel->ID.  This suprises some people, but see the
          short note after the explanation of the callback parameters.

          Note: An effort has been made to insure that when monitoring "*", "register" is first
          called with the remote kernel's unique ID, and subsequent calls are aliases.  This
          can't be guaranteed at this time, however.

       $states
          Hashref that specifies what callback states are called when something interesting
          happens.  If $state is empty or undef, the session will no longer monitor the given
          remote kernel.

   Callback states
       The following states can be monitored:

       "channel"
             Called when a channel becomes ready or goes away.  ARG3 is either "ready" or
             "close".  ARG4 is the numerical ID of the channel's session.  See "CHANNELS" below.

       "register"
             Called when a remote kernel or alias is registered.  This is equivalent to when the
             connection phase is finished.

       "unregister"
             Called when a remote kernel or alias is unregistered.  This is equivalent to when
             the remote kernel disconnects.

       "subscribe"
             Called when IKC succeeds in subscribing to a remote session.  ARG3 is an
             IKC::Specifier of what was subscribed to.  Use this for posting to the proxy
             session.

       "unsubscribe"
             Called when IKC succeeds in unsubscribing from a remote session.

       "shutdown"
             You are informed whenever someone tries to do a sane shutdown of IKC and all
             peripheral sessions.  This will called only once, after somebody posts an
             IKC/shutdown event.

       "error"
             You are informed of errors in local and remote kernels.  ARG3 is the operation that
             failed. ARG4 is the error message.  See "ERRORS" below.

       "data"
             Little bit of data (can be scalar or reference) that is passed to the callback.
             This allows you to more magic.

       The callback states are called the following parameters :

       "ARG0"
             Name of the kernel that was passed to poe://*/IKC/monitor

       "ARG1"
             ID or alias of remote kernel from IKC's point of view.

       "ARG2"
             A flag.  If this is true, then ARG1 is the remote kernel unique ID, if false, then
             ARG1 is an alias.  This is mostly useful when monitoring "*" and is in fact a bit
             bloatful.

       "ARG3"
             "$state->{data}" ie any data you want.

       "ARG4" ... "ARGN"
             Callback-specific parameters.  See above.

       Most of the time, ARG0 and ARG1 will be the same.  Exceptions are if you are monitoring
       "*" or if you supplied a full IKC event specifier to IKC/monitor rather then just a plain
       kernel name.

   Short note about monitoring all kernels with "*"
       There are 2 reasons circonstances in which you will be monitoring all remote kernels :
       names known in advance and names unknown in advance.

       If you know kernel names in advance, you might be better off monitoring a given kernel
       name.  However, you might prefer doing a case-like compare on ARG1 (with regexes, say).
       This would be useful for clustering, where various redundant kernels could follow a naming
       convention like [application]-[host], so you could compare "ARG1" with "/^credit-/" to
       find out if you want to set up specific things for that kernel.

       Not knowing the name of a kernel in advance, you could be doing some sort of autodiscovery
       or maybe just monitoring for debuging, logging or book-keeping purposes.  You obviously
       don't want to do autodiscovery for every alias of every kernel, only for the "cannonical
       name", hence the need for ARG2.

   Short note the second
       You are more then allowed (in fact, you are encouraged) to use the same callback states
       when monitoring multiple kernels.  In this case, you will find ARG0 useful for telling
       them apart.

           $kernel->post('IKC', 'monitor', '*',
                           {register=>'remote_register',
                            unregister=>'remote_unregister',
                            subscribe=>'remote_subscribe',
                            unsubscribe=>'remote_unsubscribe',
                            data=>'magic box'});

       Now remote_{register,unregister,subscribe,unsubscribe} is called for any remote kernel.

           $kernel->post('IKC', 'monitor', 'Pulse', {register=>'pulse_connected'});

       "pulse_connected" will be called in current session when you succeed in connecting to a
       kernel called 'Pulse'.

           $kernel->post('IKC', 'monitor', '*');

       Session is no longer monitoring all kernels, only 'Pulse'.

           $kernel->post('IKC', 'monitor', 'Pulse', {});

       Now we aren't even interested in 'Pulse';

CHANNELS

       Previous versions of IKC did not adequately allow you to control a connection.  With
       0.2400 we added a much needed feature.

       Each connection to a remote kernel is handled by a channel session.  You find out the
       session's ID by monitoring for "channel" operations.  You may close a channel and the
       corresponding connection to the remote kernel by sending it a "shutdown" event.

           sub _start {
               # set up the monitor
               $poe_kernel->call( IKC => monitor => '*' => { channel => 'channel' } );
           }

           sub channel {
               my( $self, $rid, $rkernel, $real, $data, $op, $channel ) = @_[ OBJECT, ARG0..$#_ ];
               return unless $real;    # only care about the real kernel ID
               if( $op eq 'ready' ) {  # new channel is ready
                   $self->{channel}{ $rkernel } = $channel;
               }
               elsif( $op eq 'close' ) {   # channel is gone
                   delete $self->{channel}{ $rkernel };
               }
           }

           # this an event posted from your controler logic
           sub close_channel {
               my( $self, $rkernel ) = @_[ OBJECT, ARG0 ];
               # tell the channel to close
               $poe_kernel->post( $self->{channel}{ $rkernel } => 'shutdown' );
           }

ERRORS

       Previous versions of IKC did not adequately allow you to monitor for errors on a
       connection.  With 0.2400 we started monitoring errors.

       There are 2 step during which you can have errors: when opening the connection and during
       message exchange.  These 2 steps are handled diffrently.

       You use "on_error" in POE::Component::IKC::Client and "on_error" in
       POE::Component::IKC::Server to receive errors while a connection is being opened.  Note
       that this includes the initial IKC handshake.

           sub on_error
           {
               my( $op, $errnum, $errstr ) = @_;
               # Handle this like you would any POE socket error
               # But remember you can't rely on your session being active
           }

       You use "monitor" on error to receive errors during message exchange.  ARG3 is the name of
       the operation.  ARG4 is the error message.  Current operations are:

       remote-request
           Remote kernel was unable to parse a request that was sent from the local kernel.

       remote-check
           Remote kernel has not published an event that was sent from the local kernel.

       remote-resolve
           Remote kernel could not find a session that could handle the request.

       remote-invocation
           Remote kernel had an error when it tried to invoke the request handler.  Please note
           this will not catch errors in the request handler, but only errors in the thunk.

       local-request
       local-check
       local-resolve
       local-invocation
           These 4 operations are the local equivalent of the previous 4.  They are intented for
           logging.  In general no actions are required.

           Note that 'local' and 'remote' refer to where the operation happened, not where the
           request originated.  As an example, kernel A sends a poe://B/foo/bar request to kernel
           B.  Kernel B has not published that event.  Monitors on kernel A will see remote-
           check.  Monitors on kernel B will see local-check.

       channel-error
           Receive channel errors during message exchange.   Channel errors are equivalent to POE
           wheel errors.  The message will be "[$errnum] $errstr".

       subscribe
           Failure to subscribe to a remote session.

       fork
           POE::Component::IKC::Server failed to fork.

       resolve
           Error when trying to find a remote kernel or session.

       Example monitor for error events:

           sub monitor_error
           {
               my( $self, $rid, $kernel, $real, $data, $op, $message ) =
                       @_[ OBJECT, ARG0 ... $#_ ];
               if( $op =~ /^channel-/ and $message =~ /\[(\d+)\] (.*)/ ) {
                   return unless $real;
                   my( $errnum, $errstr ) = ( $1, $2 );
                   if( $op eq 'channel-read' and $errnum == 0 ) {
                       warn "Connection closed";
                       return;
                   }
               }
               warn "Error during $op: $message";
           }

       In particular, you will note we don't do anything when we detect the channel closed.
       Instead, it is recommended to attempt reconnection in the "unregister" event.

EXPORTED FUNCTIONS

   "create_ikc_responder"
       DEPRECATED.  Please use

           POE::Compontent::IKC::Responder->spawn();

PROXY SENDER

       Event handlers invoked via IKC will have a proxy SENDER session. You may use it to post
       back to the remote session.

           $poe_kernel->post( $_[SENDER], 'response', @args );

       Normally this proxy session is available during the invocation of the event handler.  You
       may claim it for longer by setting an external reference:

           $heap->{remote} = $_[SENDER]->ID;
           $poe_kernel->refcount_increment( $heap->{remote}, 'MINE' );

       POE::Component::IKC will detect this and create a new proxy session for future calls.  It
       will then be UP TO YOU to free the session:

           $poe_kernel->refcount_decrement( $heap->{remote}, 'MINE' );

       Note that you will have to publish any events that will be posted back.

BUGS

       Sending session references and coderefs to a foreign kernel is a bad idea.  At some point
       it would be desirable to recurse through the paramerters and and turn any session
       references into state specifiers.

       The "rsvp" state in call is a bit problematic.  IKC allows it to be posted to once, but
       doesn't check to see if the foreign kernel is the right one.

       "retract" does not currently tell foreign kernels that have subscribed to a session/state
       about the retraction.

       "call()"ing a state in a proxied foreign session doesn't work, for obvious reasons.

AUTHOR

       Philip Gwyn, <perl-ikc at pied.nu>

COPYRIGHT AND LICENSE

       Copyright 1999-2014 by Philip Gwyn.  All rights reserved.

       This library is free software; you can redistribute it and/or modify it under the same
       terms as Perl itself.

       See <http://www.perl.com/language/misc/Artistic.html>

SEE ALSO

       POE, POE::Component::IKC::Server, POE::Component::IKC::Client,
       POE::Component::IKC::ClientLite, POE::Component::IKC::Channel, POE::Component::IKC::Proxy,
       POE::Component::IKC::Freezer, POE::Component::IKC::Specifier.