On Tue, Dec 14, 2004 at 11:39:03AM -0800, Ofer Nave wrote:
> I can see how you would frequently want to design states that could be 
> invoked in both blocking and non-blocking mode.
> 
> For example, imagine you had a session acting as a http client.  You 
> might want to design the request() handler to work in both models:
> 
> 1) [NON-BLOCKING] You could post a request event to the session, which 
> would perform the request and then send an event back to let you know 
> when it is done, or if it errored out.
> 
> 2) [BLOCKING] You could use call instead of post, if you insist on 
> performing the request immediately and getting the results back, in 
> which case there is no reason to mess with the http client session 
> sending an event back when it can simply return the web page (or error 
> code) as the return value of the call.
> 
> But, how do you elegantly implement that request method in such a way 
> that it knows what the caller wants it to do without additional "mode" 
> parameters (which are ugly)?
> 
> I suppose the blocking/call() form is akin to calling a function as 
> opposed to sending an event, and arguably shouldn't be supported in the 
> event-driven model of POE, but it is convenient sometimes.  :)

The person writing code to use the method knows whether she wants it
to block before compile time.  Why make a runtime check to determine
the intent of a coding-time decision?

I suggest having three methods:

The first method sends a request and returns immediately.

The second method assumes that part or all of a response is ready.
Perhaps it's called as a result of IO::select() or
$kernel->select_read().  It reads what it can, builds a response, and
returns a full response.  It returns undef or another indication if it
can't return a response.

The third method combines the two above, using IO::Select to block
until the response arrives.  For example:

  sub do_everything {
    my ($self, $request) = @_;
    $self->send_request($request);
    while ($self->wait_for_data()) {
      my $response = $self->receive_response();
      return $response if $response;
    }
  }

Then you'd write a component around it.  The core of which would be a
session like this one:

  POE::Session->create(
    inline_states => {
      _start => sub {
        $_[KERNEL]->alias_set(...);
        my $object = Object->new();
        $_[HEAP]->{object} = $object;
        $_[KERNEL]->select_read($object->{socket}, "got_data");
        ...;
      },
      request => sub {
        $_[HEAP]->{object}->send_request(@_[ARG0..$#_]);
        store_request_info_in_heap();
      },
      got_data => sub {
        my $response = $_[HEAP]->{object}->receive_response();
        if ($response) {
          look_up_request_info_in_heap();
          send_response_to_other_session();
          clean_up_request_info_from_heap();
        }
      },
    }
  );

Or something.  This is all spur of the moment, and I'm sure the idea
could be refined in a lot of ways.

Maybe a set of base clasess could handle most of the work (request
tracking, response posting, do_everything(), etc.).  What would remain
is customizing the object for a particular type of transaction.

-- 
Rocco Caputo - http://poe.perl.org/

Reply via email to