Squatting
view release on metacpan or search on metacpan
eg/Example/Controllers.pm view on Meta::CPAN
my $input = $self->input;
my $name = $input->{name};
my $value = $input->{value};
$self->cookies->{$name} = { -value => $value };
$self->redirect(R('Cookie'));
},
),
C(
Count => [ '/@count' ],
# Requests to the Count controller run in a separate coroutine.
# - The (continuity => 1) tells Squatting::Mapper to take notice
# of this controller and put requests to this controller in
# a different "session queue". In Continuity-speak, being in
# a different "session queue" means you get your own coroutine.
continuity => 1,
get => sub {
my ($self) = @_;
my $cr = $self->cr;
my $i = 1;
# Infinite loops are allowed in Continuity controllers.
while (1) {
# - Typically, you won't ever return control back to Squatting.
# - You're in Continuity land, now.
lib/Squatting.pm view on Meta::CPAN
=head2 Continuity and Coro
When you want to start dabbling with RESTless controllers, it would serve you
well to understand how Continuity, Coro and Event work. To learn more, I
recommend reading the POD for the following Perl modules:
L<Continuity>,
L<Coro>,
L<AnyEvent>.
Combining coroutines with an event loop is a surprisingly powerful technique.
=head2 Camping
Squatting is descended from Camping, so studying the Camping API
will indirectly teach you much of the Squatting API.
L<http://github.com/why/camping/tree/master>
=head2 Prototype-based OO
lib/Squatting/Mapper.pm view on Meta::CPAN
}
},
continuity => 1, # <--- causes Squatting::Mapper to notice
)
When it sees that C<continuity> is true, the request will be given a
session id based on: $cookie_session + $app_name + $controller_name + $path.
Normally, it's just $cookie_session, but when you get these extra pieces
added to your session id, that tells Continuity that you want to have a
separate coroutine for this request.
The primary intended use for handling requests in a separate coroutine is to
facilitate COMET event loops. When a user visits a COMET-enabled site, there
will be some JavaScript that starts a long-polling HTTP request. On the
server-side, the long-polling handler will typically have an infinite loop in
it, so it needs to sit off in its own coroutine so that it doesn't affect the
coroutine that is handling the normal, RESTful requests.
If the user decides to open multiple-tabs to the same COMET-enabled site,
each of those tabs needs to be differentiated on the server-side as well.
That's when it becomes useful to stick something random in the path.
Notice in the example that the path regex is '/@events/(\d+)'.
It would be the job of the JavaScript to append a random string of digits to
the end of an '/@events/(\d+)' URL before starting the long-poll request.
That'll let Squatting::Mapper give each tab its own coroutine as well.
=head1 SEE ALSO
L<Squatting::On::Continuity>, L<Continuity::Mapper>
=cut
# Local Variables: ***
# mode: cperl ***
# indent-tabs-mode: nil ***
lib/Squatting/On/Continuity.pm view on Meta::CPAN
$cr->next;
}
},
continuity => 1,
)
Here, the code is dropping down to the Continuity level. The C<$cr> variable
contains a L<Continuity::Request> object, and with that in hand, we can try
something as audacious as an infinite loop. However, this while loop does not
spin out of control and eat up all your CPU. The C<$cr-E<gt>next> statement
will pause execution of the current coroutine, and it will wait until the
next HTTP request to come in. Thus, you can hit reload multiple times and
watch C<$i> increment each time.
However, not just any HTTP request will wake this coroutine up. To make
C<$cr-E<gt>next> stop blocking, a request with the following properties will
have to come in.
=over 4
=item It has to have the same session_id.
=item It has to be for the same controller.
=item It has to be a GET request.
lib/Squatting/On/Continuity.pm view on Meta::CPAN
The key is this line:
queue => { get => 'name_of_queue' }
When you're squatting on Continuity, you're allowed to define your controllers
with a C<queue> attribute. It should contain a hashref where the keys are HTTP
methods (in lower case) and the values are unique strings that will be used
internally by Continuity to differentiate one queue of requests from another.
Every method mentioned in C<queue> will be given its own coroutine to run in.
=head2 Pausing for Other Events
TO BE CONTINUED...
For a sneak peak, take a look at the Chat application in the F<eg/> directory.
=head1 SEE ALSO
L<Coro>, L<Continuity>, L<Continuity::Mapper>, L<Squatting::Mapper>
lib/Squatting/With/Coro/Debug.pm view on Meta::CPAN
package Squatting::With::Coro::Debug;
#use strict;
#use warnings;
use Coro::Debug;
sub init {
my $app = shift;
my $config = \%{$app.'::CONFIG'};
my $path = $config->{'with.coro.debug.unix_domain_socket'}
|| '/tmp/squatting.with.coro.debug';
our $debug = Coro::Debug->new_unix_server($path);
$app->next::method;
}
1;
__END__
=head1 NAME
lib/Squatting/With/Coro/Debug.pm view on Meta::CPAN
squatting --module With::Coro::Debug App
From a script:
use App qw(On::Continuity With::Coro::Debug);
App->init;
App->continue();
Connect to Coro::Debug in another terminal
socat readline unix:/tmp/squatting.with.coro.debug
A Coro::Debug session looks like this:
> ps
PID SC RSS USES Description Where
142161516 RC 245k 23 [main::] [Event.pm:164]
142188912 -- 1404 4 [coro manager] [Coro.pm:358]
142189128 N- 84 0 [unblock_sub scheduler] -
142455240 N- 84 0 [Event idle process] -
146549540 -- 7340 14 [HttpDaemon.pm:426]
146549792 -- 2088 5 [Continuity.pm:436]
146552468 UC 3344 6 [Coro::Debug session] [Coro.pm:257]
=head1 DESCRIPTION
Using this module in conjunction with a Squatting app that's running on top of
Continuity will provide you with a L<Coro::Debug> server that you can connect
to using tools like C<socat>. This will let you inspect the state of your
Squatting app while its running.
=head1 CONFIG
=over 4
=item with.coro.debug.unix_domain_socket
This should be a string that represents the path of the Unix domain socket
that Coro::Debug will use. If this option is not set, the default value
is F</tmp/squatting.with.coro.debug>.
B<Example>
$CONFIG{'with.coro.debug.unix_domain_socket'} = '/tmp/coro-debug-socket';
=back
=head1 SEE ALSO
=head2 Perl Modules
L<Coro>,
L<Coro::Debug>,
L<Continuity>,
( run in 0.643 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )