package Continuity::Inspector; use strict; use Data::Dumper; use Coro; use Coro::Semaphore; # Accessors sub debug_level { exists $_[1] ? $_[0]->{debug_level} = $_[1] : $_[0]->{debug_level} } sub debug_callback { exists $_[1] ? $_[0]->{debug_callback} = $_[1] : $_[0]->{debug_callback} } =head1 NAME Continuity::Inspector =head1 DESCRIPTION Implements the same API as the "Request" objects created by L and other adapters. These faked request objects go over the request queue but instead of containing a request from a user, they contain a request from another part of the system. Use L instead. =head2 C<< new(callback => sub { ... } ) >> Call with the code to run in another coroutine's execution context. The execution context includes the call stack, including all of the data returned by L, L, L, and so on. One Inspector instance can be reused but can only on one context at a time or else the locking stuff will probably go all breaky. =cut sub new { my $class = shift; my %args = @_; my $self = { peeks_pending => undef, # requester => $args{requester}, # pointless callback => $args{callback}, debug_level => $args{debug_level} || 1, debug_callback => $args{debug_callback} || sub { print "@_\n" }, }; bless $self, $class; return $self; } =head2 C<< $inspector->inspect( $session_queue ) >> It's a bit silly that this is here but having it here helps with locking. L has a bit nicer interface to the same thing. =cut sub inspect { my $self = shift; my $queue = shift or return; $self->{peeks_pending} = Coro::Semaphore->new(0); $queue->put($self); $self->{peeks_pending}->down; return 1; } sub immediate { my $self = shift; $self->{callback}->(); $self->{peeks_pending}->up; # ${ $self->{peeks_pending} } = 0; return 1; } # fake enough of the API that Continuity::RequestHolder doesn't blow up sub end_request { } sub send_basic_header { } sub close { } sub send_error { } sub print { warn "Printing from inspector! You probably don't want this...\n"; } 1;