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/