File Coverage

blib/lib/Dancer2/Plugin/Role/Shutdown.pm
Criterion Covered Total %
statement 55 61 90.1
branch 13 22 59.0
condition 7 14 50.0
subroutine 11 11 100.0
pod 3 3 100.0
total 89 111 80.1


line stmt bran cond sub pod time code
1 1     1   675 use strictures 2;
  1         7  
  1         39  
2              
3             package # for internal use only
4             Dancer2::Plugin::Role::Shutdown;
5              
6             # ABSTRACT: Role for L
7              
8 1     1   221 use Carp qw(croak);
  1         2  
  1         62  
9 1     1   5 use Class::Load qw(load_class);
  1         1  
  1         47  
10 1     1   5 use Scalar::Util qw(blessed);
  1         2  
  1         50  
11 1     1   5 use Moo::Role 2;
  1         14  
  1         6  
12              
13 1     1   374 use constant NORMAL => 0;
  1         1  
  1         87  
14 1     1   5 use constant GRACEFUL => 1;
  1         2  
  1         803  
15              
16             our $VERSION = '0.001'; # VERSION
17              
18             has shared => (
19             is => 'rwp',
20             default => sub { {} },
21             );
22              
23             has validator => (
24             is => 'rw',
25             default => sub {
26             sub {
27             my ( $app, $rest, $sessid ) = @_;
28             return unless $sessid;
29             my $sx = $app->session->expires // 0;
30             $app->session->expires($rest) if $rest > $sx;
31             $app->response->header(
32             Warning => "199 Application shuts down in $rest seconds" );
33             return 1;
34             }
35             }
36             );
37              
38             sub has_valid_session {
39 5     5 1 310 my $app = shift;
40              
41 5   50     108 my $engine = $app->session_engine // return;
42              
43 5 50       61 return if $app->has_destroyed_session;
44              
45 5   100     27 my $session_cookie = $app->cookie( $engine->cookie_name ) // return;
46 3   50     1525 my $session_id = $session_cookie->value // return;
47              
48 3         155 eval { $engine->retrieve( id => $session_id ) };
  3         16  
49 3 50       1050 return if $@;
50              
51 3         10 return $session_id;
52             }
53              
54             sub session_status {
55 1     1 1 233 my $app = shift;
56              
57 1   50     26 my $engine = $app->session_engine // return "unsupported";
58              
59 1 50       14 return "destroyed" if $app->has_destroyed_session;
60              
61 1   50     5 my $session_cookie = $app->cookie( $engine->cookie_name )
62             // return "missing";
63 0   0     0 my $session_id = $session_cookie->value // return "empty";
64              
65 0         0 eval { $engine->retrieve( id => $session_id ) };
  0         0  
66 0 0       0 return "invalid" if $@;
67              
68 0         0 return "ok";
69             }
70              
71             sub before_hook {
72 7     7 1 16 my $self = shift;
73 7 100       51 return unless $self->shared->{state};
74 3         12 my $app = $self->app;
75 3         12 my $time = $self->shared->{final};
76 3         24 my $rest = $time - time;
77 3 100       18 if ( $rest < 0 ) {
    50          
78 1         10 $self->status(503);
79 1         231 $self->halt;
80             }
81             elsif ( $self->shared->{state} == GRACEFUL ) {
82 2 50       11 if ( my $validator = $self->validator ) {
83 2         6 my $sessid = has_valid_session($app);
84 2 100       142 unless ( $validator->( $app, $rest, $sessid ) ) {
85 1         20 $self->status(503);
86 1         125 $self->halt;
87             }
88             }
89             }
90             else {
91 0         0 croak "bad state: " . $self->shared->{state};
92             }
93             }
94              
95             sub _shutdown_at {
96 1     1   106 my $self = shift;
97 1 50       22 croak "a validator isn't installed yet"
98             unless ref $self->validator eq 'CODE';
99 1   50     4 my $time = shift // 0;
100 1 50       5 if ( $time < time ) {
101 1         2 $time += time;
102             }
103 1         5 $self->shared->{final} = $time;
104 1         4 $self->shared->{state} = GRACEFUL;
105 1         4 return $time;
106             }
107              
108             1;
109              
110             __END__