File Coverage

blib/lib/Dancer2/Core/Runner.pm
Criterion Covered Total %
statement 80 90 88.8
branch 20 26 76.9
condition 8 11 72.7
subroutine 18 18 100.0
pod 0 7 0.0
total 126 152 82.8


line stmt bran cond sub pod time code
1             # ABSTRACT: Top-layer class to start a dancer app
2             $Dancer2::Core::Runner::VERSION = '0.400000';
3             use Moo;
4 140     140   171854 use Carp 'croak';
  140         17103  
  140         934  
5 140     140   50479 use Module::Runtime 'require_module';
  140         329  
  140         10750  
6 140     140   2678 use Dancer2::Core::MIME;
  140         6135  
  140         1274  
7 140     140   7971 use Dancer2::Core::Types;
  140         335  
  140         3822  
8 140     140   812 use Dancer2::Core::Dispatcher;
  140         305  
  140         1332  
9 140     140   1213804 use Plack::Builder qw();
  140         462  
  140         4360  
10 140     140   66397 use Ref::Util qw< is_ref is_regexpref >;
  140         297002  
  140         3346  
11 140     140   982  
  140         317  
  140         160704  
12             # Hashref of configurable items for the runner.
13             # Defaults come from ENV vars. Updated via global triggers
14             # from app configs.
15             has config => (
16             is => 'ro',
17             isa => HashRef,
18             lazy => 1,
19             builder => '_build_config',
20             );
21              
22             # FIXME: i hate this
23             has mime_type => (
24             is => 'ro',
25             isa => InstanceOf ['Dancer2::Core::MIME'],
26             default => sub { Dancer2::Core::MIME->new(); },
27             );
28              
29             has server => (
30             is => 'ro',
31             isa => InstanceOf['HTTP::Server::PSGI'],
32             lazy => 1,
33             builder => '_build_server',
34             handles => ['run'],
35             );
36              
37             has apps => (
38             is => 'ro',
39             isa => ArrayRef,
40             default => sub { [] },
41             );
42              
43             has postponed_hooks => (
44             is => 'ro',
45             isa => HashRef,
46             default => sub { +{} },
47             );
48              
49             has environment => (
50             is => 'ro',
51             isa => Str,
52             required => 1,
53             default => sub {
54             $ENV{DANCER_ENVIRONMENT} || $ENV{PLACK_ENV} || 'development'
55             },
56             );
57              
58             has host => (
59             is => 'ro',
60             lazy => 1,
61             default => sub { $_[0]->config->{'host'} },
62             );
63              
64             has port => (
65             is => 'ro',
66             lazy => 1,
67             default => sub { $_[0]->config->{'port'} },
68             );
69              
70             has timeout => (
71             is => 'ro',
72             lazy => 1,
73             default => sub { $_[0]->config->{'timeout'} },
74             );
75              
76             my $self = shift;
77              
78 1     1   422 require_module('HTTP::Server::PSGI');
79             HTTP::Server::PSGI->new(
80 1         4 host => $self->host,
81 1         32291 port => $self->port,
82             timeout => $self->timeout,
83             server_software => "Perl Dancer2 " . Dancer2->VERSION,
84             );
85             }
86              
87             my $self = shift;
88              
89             $ENV{PLACK_ENV}
90 155     155   1594 and $ENV{DANCER_APPHANDLER} = 'PSGI';
91              
92             return {
93 155 100       673 behind_proxy => 0,
94             apphandler => ( $ENV{DANCER_APPHANDLER} || 'Standalone' ),
95             traces => ( $ENV{DANCER_TRACES} || 0 ),
96             host => ( $ENV{DANCER_SERVER} || '0.0.0.0' ),
97             port => ( $ENV{DANCER_PORT} || '3000' ),
98             no_server_tokens => ( defined $ENV{DANCER_NO_SERVER_TOKENS} ?
99             $ENV{DANCER_NO_SERVER_TOKENS} :
100             0 ),
101             startup_info => ( defined $ENV{DANCER_STARTUP_INFO} ?
102             $ENV{DANCER_STARTUP_INFO} :
103             1 ),
104             };
105             }
106 155 100 100     5806  
    100 100        
      50        
      50        
107             my $self = shift;
108              
109             # Enable traces if set by ENV var.
110             if (my $traces = $self->config->{traces} ) {
111 155     155 0 3375 require_module('Carp');
112             $Carp::Verbose = $traces ? 1 : 0;
113             };
114 155 100       2402  
115 1         21 # set the global runner object if one doesn't exist yet
116 1 50       34 # this can happen if you create one without going through Dancer2
117             # which doesn't trigger the import that creates it
118             defined $Dancer2::runner
119             or $Dancer2::runner = $self;
120             }
121              
122 155 100       4481 my $self = shift;
123             my $app = shift;
124              
125             push @{ $self->apps }, $app;
126              
127 198     198 0 3272 # add postponed hooks to our psgi app
128 198         394 $self->add_postponed_hooks( $app->name, $app->postponed_hooks );
129             }
130 198         416  
  198         1064  
131             my $self = shift;
132             my $name = shift;
133 198         1406 my $hooks = shift;
134              
135             # merge postponed hooks
136             @{ $self->{'postponed_hooks'}{$name} }{ keys %{$hooks} } = values %{$hooks};
137 198     198 0 417 }
138 198         413  
139 198         333 # decide what to start
140             # do we just return a PSGI app
141             # or do we actually start a development standalone server?
142 198         352 my $self = shift;
  198         1038  
  198         472  
  198         614  
143             my $app = $self->psgi_app;
144              
145             # we decide whether we return a PSGI coderef
146             # or spin a local development PSGI server
147             $self->config->{'apphandler'} eq 'PSGI'
148             and return $app;
149 2     2 0 831  
150 2         6 # FIXME: this should not include the server tokens
151             # since those are already added to the server itself
152             $self->start_server($app);
153             }
154 2 50       29  
155             my $self = shift;
156             my $app = shift;
157              
158             # does not return
159 0         0 $self->print_banner;
160             $self->server->run($app);
161             }
162              
163 1     1 0 453 my ($self, $apps) = @_;
164 1         3  
165             if ( $apps && @{$apps} ) {
166             my @found_apps = ();
167 1         4  
168 1         23 foreach my $app_req ( @{$apps} ) {
169             if ( is_regexpref($app_req) ) {
170             # find it in the apps registry
171             push @found_apps,
172 30     30 0 101 grep +( $_->name =~ $app_req ), @{ $self->apps };
173             } elsif ( ref $app_req eq 'Dancer2::Core::App' ) {
174 30 100 66     158 # use it directly
  8         35  
175 8         17 push @found_apps, $app_req;
176             } elsif ( !is_ref($app_req) ) {
177 8         13 # find it in the apps registry
  8         28  
178 14 100       51 push @found_apps,
    100          
    50          
179             grep +( $_->name eq $app_req ), @{ $self->apps };
180             } else {
181 6         12 croak "Invalid input to psgi_app: $app_req";
  6         86  
182             }
183             }
184 4         7  
185             $apps = \@found_apps;
186             } else {
187             # dispatch over all apps by default
188 4         6 $apps = $self->apps;
  4         28  
189             }
190 0         0  
191             my $dispatcher = Dancer2::Core::Dispatcher->new( apps => $apps );
192              
193             # initialize psgi_apps
194 8         19 # (calls ->finish on the apps and create their PSGI apps)
195             # the dispatcher caches that in the attribute
196             # so ->finish isn't actually called again if you run this method
197 22         114 $dispatcher->apps_psgi;
198              
199             return sub {
200 30         468 my $env = shift;
201              
202             # mark it as an old-style dispatching
203             $self->{'internal_dispatch'} = 1;
204              
205             my $response = $dispatcher->dispatch($env);
206 30         34206  
207             # unmark it
208             delete $self->{'internal_dispatch'};
209 72     72   378974  
210             # cleanup
211             delete $self->{'internal_sessions'};
212 72         283  
213             return $response;
214 72         332 };
215             }
216              
217 72         259 my $self = shift;
218             my $pid = $$;
219              
220 72         2068 # we only print the info if we need to
221             $self->config->{'startup_info'} or return;
222 72         479  
223 30         1066 # bare minimum
224             print STDERR ">> Dancer2 v" . Dancer2->VERSION . " server $pid listening "
225             . 'on http://'
226             . $self->host . ':'
227 1     1 0 2 . $self->port . "\n";
228 1         3  
229             # all loaded plugins
230             foreach my $module ( grep { $_ =~ m{^Dancer2/Plugin/} } keys %INC ) {
231 1 50       20 $module =~ s{/}{::}g; # change / to ::
232             $module =~ s{\.pm$}{}; # remove .pm at the end
233             my $version = $module->VERSION;
234 0            
235             defined $version or $version = 'no version number defined';
236             print STDERR ">> $module ($version)\n";
237             }
238             }
239              
240 0           1;
  0            
241 0            
242 0            
243 0           =pod
244              
245 0 0         =encoding UTF-8
246 0            
247             =head1 NAME
248              
249             Dancer2::Core::Runner - Top-layer class to start a dancer app
250              
251             =head1 VERSION
252              
253             version 0.400000
254              
255             =head1 AUTHOR
256              
257             Dancer Core Developers
258              
259             =head1 COPYRIGHT AND LICENSE
260              
261             This software is copyright (c) 2022 by Alexis Sukrieh.
262              
263             This is free software; you can redistribute it and/or modify it under
264             the same terms as the Perl 5 programming language system itself.
265              
266             =cut