Skip to content

Commit 4af1e56

Browse files
committed
Adjust TH to the newest PAGI::Tools
1 parent 9605eb2 commit 4af1e56

11 files changed

Lines changed: 84 additions & 33 deletions

File tree

cpanfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ on 'test' => sub {
33
};
44

55
requires 'perl' => '5.040';
6-
requires 'PAGI' => '0.001023';
6+
requires 'PAGI::Tools' => '0.002000';
77
requires 'Gears' => '0.104';
88
requires 'Mooish::Base' => '1.005';
99
requires 'Future::AsyncAwait' => 0;

ex/full-app/lib/FullApp/Controller/API.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ sub flatten_locations ($self, $level)
2727
return @out;
2828
}
2929

30-
async sub list_locations ($self, $ctx)
30+
sub list_locations ($self, $ctx)
3131
{
3232
my @locations = map {
3333
+{
@@ -39,6 +39,6 @@ async sub list_locations ($self, $ctx)
3939
}
4040
} $self->flatten_locations($self->router);
4141

42-
await $ctx->res->json(\@locations);
42+
$ctx->res->json(\@locations);
4343
}
4444

lib/Thunderhorse.pm

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ sub build_handler ($controller, $destination)
110110
}
111111
}
112112

113+
# this needs to be here, since we want to use $send from this context
114+
await $ctx->try_send_res;
115+
113116
# if this is a bridge and bridge did not render, it means we are
114117
# free to go deeper. Avoid first match, as it was handled already
115118
# above
@@ -390,27 +393,27 @@ it is equally easy to do something else. Take the following destination example:
390393
391394
async sub send_custom ($self, $ctx)
392395
{
393-
await $ctx->res->text('Plaintext response');
396+
$ctx->res->text('Plaintext response');
394397
return 'this will not get rendered';
395398
}
396399
397400
This takes response (L<Thunderhorse::Response>) from context, and sends
398401
plaintext manually. This action I<consumes> the context, marking it as
399-
finished. In this case, return value of the destination is ignored. Note that
400-
the await call on C<< ->text >> method is mandatory.
402+
finished. In this case, return value of the destination is ignored.
403+
401404
402405
Another example:
403406
404407
sub send_custom2 ($self, $ctx)
405408
{
406-
$ctx->res->status(400)->content_type('text/plain');
407-
return 'this is rendered as plaintext and status 400';
409+
$ctx->res->content_type('text/plain');
410+
return 'this is rendered as plaintext';
408411
}
409412
410413
This time, the return value of the destination is not ignored, since only
411414
setting response metadata does not cause the context to be consumed. Status and
412415
I<Content-Type> header will not be overridden, so the response will be sent as
413-
plaintext. In this case, there is no need to await anything.
416+
plaintext.
414417
415418
While not very common, a destination can be unimplemented when C<to> is
416419
skipped. Unimplemented locations will be "stepped over" during request

lib/Thunderhorse/App.pm

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ async sub pagi ($self, $scope, $receive, $send)
207207
# 404 is possible even if we had matches, as long as no handler consumed
208208
# the context
209209
if (!$ctx->is_consumed) {
210-
await $self->render_error(undef, $ctx, 404);
210+
$self->render_error(undef, $ctx, 404);
211+
await $ctx->send_res;
211212
}
212213

213214
return;
@@ -240,15 +241,12 @@ sub run ($self)
240241
async sub render_error ($self, $controller, $ctx, $code, $message = undef)
241242
{
242243
$message = defined $message && !$self->is_production ? $message : status_message($code);
243-
await $ctx->res->status($code)->text($message);
244+
$ctx->new_res->status($code)->text($message);
244245
}
245246

246247
async sub render_response ($self, $controller, $ctx, $result)
247248
{
248-
await $ctx->res
249-
->status_try(200)
250-
->content_type_try('text/html')
251-
->send($result);
249+
$ctx->res->status_try(200)->html($result);
252250
}
253251

254252
#########################

lib/Thunderhorse/Context.pm

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use Mooish::Base -standard;
55

66
use Devel::StrictMode;
77

8+
use Future::AsyncAwait;
89
use Thunderhorse::Request;
910
use Thunderhorse::Response;
1011
use Thunderhorse::WebSocket;
@@ -32,7 +33,8 @@ has field 'req' => (
3233

3334
has field 'res' => (
3435
(STRICT ? (isa => InstanceOf ['Thunderhorse::Response']) : ()),
35-
default => sub ($self) { Thunderhorse::Response->new(context => $self) },
36+
lazy => sub ($self) { Thunderhorse::Response->new(context => $self) },
37+
clearer => -hidden,
3638
);
3739

3840
# NOTE: websocket must be lazy, because it will die if scope is not websocket
@@ -105,11 +107,54 @@ sub consume ($self)
105107
sub is_consumed ($self)
106108
{
107109
return $self->_consumed
108-
|| $self->res->is_sent
110+
|| $self->_res_sent
111+
|| $self->res->is_ready
109112
|| ($self->has_ws && $self->ws->is_closed)
110113
|| ($self->has_sse && $self->sse->is_closed);
111114
}
112115

116+
sub _res_sent ($self)
117+
{
118+
return !!$self->scope->{'pagi.response.sent'};
119+
}
120+
121+
sub new_res ($self)
122+
{
123+
$self->_clear_res;
124+
return $self->res;
125+
}
126+
127+
sub _send_res ($self)
128+
{
129+
# NOTE: PAGI scope key - avoid "true" for better portability
130+
# NOTE: returns a promise
131+
$self->scope->{'pagi.response.sent'} = 1;
132+
return $self->res->respond($self->sender);
133+
}
134+
135+
async sub send_res ($self)
136+
{
137+
# NOTE: we check a general pagi key, but raise a thunderhorse exception -
138+
# should it just die()?
139+
Gears::X::Thunderhorse->raise('response was already sent')
140+
if $self->_res_sent;
141+
142+
await $self->_send_res;
143+
144+
return;
145+
}
146+
147+
async sub try_send_res ($self)
148+
{
149+
return
150+
if $self->_res_sent;
151+
152+
await $self->_send_res
153+
if $self->res->is_ready;
154+
155+
return;
156+
}
157+
113158
__END__
114159
115160
=head1 NAME
@@ -124,7 +169,7 @@ Thunderhorse::Context - Request handling context
124169
my $stashed_value = $ctx->stash->get('key');
125170
my $session_value = $ctx->session->get('key');
126171
127-
await $ctx->res->text("Hello World");
172+
$ctx->res->text("Hello World");
128173
}
129174
130175
=head1 DESCRIPTION

lib/Thunderhorse/Controller.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ Thunderhorse::Controller - Base controller class for Thunderhorse
117117
118118
async sub show ($self, $ctx, $id)
119119
{
120-
await $ctx->res->text("User ID: $id");
120+
$ctx->res->text("User ID: $id");
121121
}
122122
123123
=head1 DESCRIPTION

lib/Thunderhorse/Cookbook.pod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ L<Thunderhorse::App/render_error>:
2121
$html = $controller->template('error/error', {title => status_message($code)});
2222
}
2323

24-
await $ctx->res->status($code)->html($html);
24+
$ctx->res->status($code)->html($html);
2525
}
2626

2727
For example for error 404, code above will try to render C<error/404.tt>

lib/Thunderhorse/Response.pm

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,17 @@ sub FOREIGNBUILDARGS ($class, %args)
1313
Gears::X::Thunderhorse->raise('no context for response')
1414
unless $args{context};
1515

16-
return $args{context}->pagi->@[0, 2];
16+
return ($args{context}->pagi->[0]);
1717
}
1818

1919
sub update ($self, $scope, $receive, $send)
2020
{
2121
$self->{scope} = $scope;
22-
$self->{send} = $send;
22+
}
23+
24+
sub is_ready ($self)
25+
{
26+
return $self->has_body_source || $self->has_status;
2327
}
2428

2529
__END__
@@ -32,9 +36,9 @@ Thunderhorse::Response - Response wrapper for Thunderhorse
3236
3337
async sub show ($self, $ctx, $id)
3438
{
35-
await $ctx->res->text("Hello World");
36-
await $ctx->res->json({data => 'value'});
37-
await $ctx->res->redirect('/login');
39+
$ctx->res->text("Hello World");
40+
$ctx->res->json({data => 'value'});
41+
$ctx->res->redirect('/login');
3842
}
3943
4044
=head1 DESCRIPTION

t/base.t

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ package BasicApp {
4444
$router->add(
4545
'/preset_headers/?ex_code' => {
4646
to => sub ($self, $ctx, $code) {
47-
$ctx->res->status(201)->content_type('application/xml');
47+
$ctx->res->content_type('application/xml; charset=utf-8');
4848
Gears::X::HTTP->raise($code, 'test')
4949
if $code;
5050

@@ -134,7 +134,7 @@ subtest 'should render text set by res->text' => sub {
134134

135135
subtest 'should render without overriding set headers' => sub {
136136
http $app, GET '/preset_headers';
137-
http_status_is 201;
137+
http_status_is 200;
138138
http_header_is 'content-type', 'application/xml; charset=utf-8';
139139
http_text_is 'this gets rendered as xml';
140140
};

t/facade.t

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ package FacadeApp::Controller::Test::Facade {
1616
async sub send_something_later ($self)
1717
{
1818
await $self->app->loop->delay_future(after => 0.5);
19-
await $self->res->text('Something');
19+
$self->res->text('Something');
20+
await $self->send_res;
2021
}
2122
}
2223

0 commit comments

Comments
 (0)