Lately I've been developing a skunkworks project to standardize POE::Component, code named POE::Stage.
I'm happy with its progress so far, and I thought I would share it with a wider audience. Subversion can fetch a copy of the source from https://thirdlobe.com/svn/poe-stage/ . You can also browse the source there, but http://thirdlobe.com/projects/poe-stage/browser/ might be nicer. To be sure, I have ulterior motives for opening the project: I don't have as much time to devote to it as I would like. It's my hope that people will fall in love with the idea and offer to help it see fruition. Please contact me for a developer account if my plan works. To help whet your appetite, the rest of this message describes some of POE::Stage's labor-saving features. Barring any unforseen bugs, they work now. Standardize and simplify the calling convention for message handlers. sub begin_request { my ($self, $args) = @_; while (my ($arg, $value) = each %$args) { print "$arg = $value\n"; } } Maintain state between requests and responses, albeit at the expense of using special data members. # $self->{req} refers to the current request being handled by this # object. Things stored under $self->{req} persist for the duration # of the current request. sub begin_request { my ($self, $args) = @_; $self->{req}{foo} = POE::Request->new( ... ); $self->{req}{foo}{data} = "persists for the request"; } # $self->{rsp} refers to the current response being handled. Data # beneath $self->{rsp} corresponds to data stored under the request # that prompted it. sub handle_response { my ($self, $args) = @_; print "$self->{rsp}{data}\n"; # "persists for the request" } Requests can be used as response channels. sub handle_request { my ($self, $args) = @_; if ($args->{socket}) { $self->{req}->return( _type => "success", socket => $args->{socket}, ); return; } $self->{req}->return( _type => "failure", errnum => $args->{error_number}, errstr => $args->{error_message}, ); } Standardize request messages, and map response types to methods at request time. sub begin_request { my ($self, $args) = @_; # Create a request. On success, pass a successful response to my # interact() method. On failure, pass the failure response to # log_error(). $self->{req}{foo} = POE::Request->new( _stage => $object, _method => "method_name", _on_success => "interact", _on_failure => "log_error" ); } Everything is automatically cleaned up when a request is canceled or a response is generated. POE::Stage wraps timers and I/O event watchers in POE::Watcher objects. These objects automatically clean up the underlying POE::Kernel resources when they destruct. Canceling or concluding a request causes its data scope to be destroyed. As long as POE::Watcher objects are scoped to the requests they belong to, they will self-destruct and clean up at the proper times. sub handle_request { my ($self, $args) = @_; $self->{req}{timeout} = POE::Watcher::Delay->new( ... ); } $self->{req}->return(...) terminates the current request as a side effect, ensuring timers and I/O watchers associated with $self->{req} are cleaned up. Likewise a requester can cancel a request it has made by allowing it to destruct. delete($self->{req}{foo}) cancels $self->{req}{foo}. Finally, the convention of storing new requests within the current request causes request destruction to be chained. Canceling a top-level request will also cancel the tree of sub-requests beneath it. Thanks for reading. -- Rocco Caputo - http://poe.perl.org/
