On Apr 5, 2011, at 12:45, Michael R. Davis wrote:

> POE Folks,
> I've not used POE before but have plans to use a POE capability shortly.  
> Last night I added a POE::Session wrapper in my Net::GPSD3 (v0.15) package 
> but I'm not entirely sure it's using best practices.
> 
> http://search.cpan.org/dist/Net-GPSD3/lib/Net/GPSD3/POE.pm
> 
> Specifically, should I use a more specific HEAP key than "wheel".
> 
> $heap->{"wheel"}=...

You may call it whatever you like.  More specific names are good because they 
help make the code more readable.

> I've also not seen any best practices about passing the parent object around 
> in HEAP.
> 
> $heap->{"gpsd"}=$self;

Using object_states instead of inline_states makes sense in your case.  All 
your callbacks are essentially object methods.  Here's an untested rewrite of 
the guts of Net::GPSD3::POE.  I'm sure it's not quite functional, but I hope 
it's a good example.

### Called as a plain method, not a POE callback.
# @_ is $self and whatever the caller provides.

# In this case, object_states are being used because the callbacks are
# object methods.  The $_[OBJECT] parameter will be populated with the
# $self for the callback.  This eliminates the need to store $self
# explicitly.

sub start_session {
  my $self = shift;    #ISA Net::GPSD::POE

  # Don't start another one.
  return if $self->{sid};

  $self->{sid} = POE::Session->create(
    object_states => [
      $self         => {
        _start      => '_handle_poe_start',
        input_event => '_handle_input_event',
        shutdown    => '_handle_poe_shutdown',
      },
    ]
  )->ID();
}

# POE callback.  Start the session's resources.  We're skipping
# $_[HEAP] altogether because the original code only shows need for
# one I/O watcher per object.  We can use a single name for the
# ReadWrite resource ("io").  If we were managing multiple wheels,
# then we might create a hash of them keyed on wheel ID.

sub _handle_poe_start {
  my $self = $_[OBJECT];

  $self->{io} = POE::Wheel::ReadWrite->new(
    InputEvent => "input_event",
    Handle     => $self->socket(),
    Filter     => POE::Filter::Line->new(
      InputLiteral  => "\r\n",
      OutputLiteral => "\n",
    ),
  );

  $self->{io}->put(qq(?WATCH={"enable":true,"json":true};));
},

### Called as a plain method, not a POE callback.
# @_ is $self and whatever the caller provides.
#
# This method asks the session to clean up and stop.  POE's session
# encapsulation makes it difficult (but not impossible---this is Perl)
# to release another session's resources.

sub stop_session {
  my $self = shift;

  # Don't re-stop a dead one.
  return unless $self->{sid};

  $poe_kernel->call($self->{sid}, "shutdown");
  $self->{sid} = undef;
}

# POE callback.  Deletes the wheel from within the context of the
# session that owns it.

sub _handle_poe_shutdown {
  my $self = $_[OBJECT];
  delete $self->{io};
}

# POE callback.  Handle input.

sub _handle_input_event {
  my ($self, $line) = @_[OBJECT, ARG0];

  my @handler = $self->handlers();
  push @handler, \&Net::GPSD3::default_handler unless @handler;

  my $object = $self->constructor($self->decode($line), string => $line);
  foreach my $handler (@handler) {
    $handler->($object);
  }

  $self->cache($object);
}

-- 
Rocco Caputo <rcap...@pobox.com>

Reply via email to