File Coverage

blib/lib/Dancer2/Plugin/ProgressStatus.pm
Criterion Covered Total %
statement 63 76 82.8
branch 16 30 53.3
condition 3 12 25.0
subroutine 14 15 93.3
pod n/a
total 96 133 72.1


line stmt bran cond sub pod time code
1             # ABSTRACT: Keeps track of progress status
2              
3             package Dancer2::Plugin::ProgressStatus;
4             $Dancer2::Plugin::ProgressStatus::VERSION = '0.016';
5 1     1   415049 use strict;
  1         2  
  1         32  
6 1     1   5 use warnings;
  1         1  
  1         27  
7              
8 1     1   4 use Digest::MD5 qw/md5_hex/;
  1         1  
  1         51  
9 1     1   681 use Path::Tiny;
  1         9833  
  1         57  
10 1     1   7 use File::Path qw//;
  1         2  
  1         12  
11 1     1   4 use Carp;
  1         1  
  1         49  
12 1     1   706 use JSON qw//;
  1         8914  
  1         21  
13              
14 1     1   438 use Dancer2::Plugin;
  1         2099  
  1         6  
15 1     1   1083 use Dancer2::Plugin::ProgressStatus::Object;
  1         3  
  1         33  
16 1     1   6 use Dancer2::Core::Response;
  1         1  
  1         668  
17              
18             sub _progress_status_file {
19 9     9   15 my ( $dsl, $name ) = @_;
20              
21 9 50       38 my $dir = $dsl->config->{'plugins'}->{ProgressStatus}->{dir}
22             or croak 'No ProgressStatus plugin settings in config';
23 9 50       1007 if ( !-d $dir ) {
24 0 0       0 File::Path::make_path($dir) or die "Cannot create path $dir";
25             }
26              
27 9         113 return Path::Tiny::path($dir, md5_hex($name));
28             }
29              
30              
31             on_plugin_import {
32             my $dsl = shift;
33              
34             # determine if there is a prefix?
35              
36             # Register the route for fetching messages
37             $dsl->app->add_route(
38             method => 'get',
39             regexp => '/_progress_status/:name',
40             code => sub {
41             my $context = shift;
42             my $data = _get_progress_status_data($dsl, $context->request->params->{'name'});
43              
44             return Dancer2::Core::Response->new(
45             status => 200,
46             content => JSON->new->encode($data),
47             content_type => 'application/json',
48             );
49             },
50             );
51             };
52              
53             sub _get_progress_status_data {
54 4     4   125 my ($dsl, $name) = @_;
55              
56 4         16 my $file = $dsl->_progress_status_file($name);
57 4 50       190 if ( !$file->is_file ) {
58             return {
59 0         0 error => "No such progress status $name",
60             status => 'error',
61             };
62             }
63 4         173 my $data = JSON->new->decode($file->slurp_utf8());
64 4         710 delete $data->{pid};
65              
66 4         17 return $data;
67             }
68              
69              
70             register start_progress_status => sub {
71 5     5   147466 my ($dsl, $args) = @_;
72              
73 5 100       23 if ( !ref($args) ) {
74 3         11 $args = { name => $args };
75             }
76              
77 5         30 my $progress_id = $dsl->params->{progress_id};
78 5         223 my $name = delete $args->{name};
79 5 50 66     23 if ( !$name && !$progress_id ) {
80 0         0 croak 'Must supply name and/or progress_id';
81             }
82 5 100       17 $name .= $progress_id if $progress_id;
83              
84 5         22 my $file = $dsl->_progress_status_file($name);
85 5 100       224 if ( $file->is_file ) {
86 1         34 my $d = JSON->new->decode($file->slurp_utf8());
87 1         143 my $in_progress = $d->{in_progress};
88              
89 1 50 33     6 if ( $in_progress && $d->{pid} != $$ ) {
    50          
90 0 0       0 if ( kill(0, $d->{pid}) ) {
91 0         0 die "Progress status $name already exists for a running process, cannot create a new one\n";
92             }
93             }
94             elsif ( $in_progress ) {
95 1         31 die "Progress status $name already exists\n";
96             }
97             }
98              
99             my %objargs = (
100             _on_save => sub {
101 20     20   23 my ($obj, $is_finished) = @_;
102 20 100       622 my $data = JSON->new->encode({
103             start_time => $obj->start_time,
104             current_time => $obj->current_time,
105             total => $obj->total,
106             count => $obj->count,
107             messages => $obj->messages,
108             in_progress => $is_finished ? JSON::false : JSON::true,
109             status => $obj->status,
110             pid => $$,
111             });
112              
113 20         529 $file->spew_utf8($data);
114             },
115 4         218 );
116              
117 4         15 foreach my $key (qw/total count status messages/) {
118 16 100       36 if ( $args->{$key} ) {
119 2         5 $objargs{$key} = $args->{$key};
120             }
121             }
122              
123 4         114 my $obj = Dancer2::Plugin::ProgressStatus::Object->new(%objargs);
124 4         55 $obj->save();
125 4         2704 return $obj;
126             };
127              
128             register is_progress_running => sub {
129 0     0     my ( $dsl, $name ) = @_;
130 0           my $file = $dsl->_progress_status_file($name);
131              
132 0 0         if ( $file->exists ) {
133 0           my $d = JSON->new->decode($file->slurp_utf8());
134 0           my $in_progress = $d->{in_progress};
135              
136 0 0 0       if ( $in_progress && $d->{pid} != $$ && kill(0, $d->{pid}) ) {
      0        
137 0           return 1;
138             }
139             }
140 0           return 0;
141             };
142              
143              
144             register_plugin;
145              
146              
147             1;
148              
149             __END__