File Coverage

blib/lib/Dancer2/Core/Role/SessionFactory/File.pm
Criterion Covered Total %
statement 48 59 81.3
branch 15 32 46.8
condition 0 3 0.0
subroutine 11 12 91.6
pod 0 1 0.0
total 74 107 69.1


line stmt bran cond sub pod time code
1             package Dancer2::Core::Role::SessionFactory::File;
2             # ABSTRACT: Role for file-based session factories
3             $Dancer2::Core::Role::SessionFactory::File::VERSION = '2.0.1';
4 6     6   362968 use Moo::Role;
  6         19785  
  6         47  
5             with 'Dancer2::Core::Role::SessionFactory';
6              
7 6     6   3761 use Carp 'croak';
  6         14  
  6         1491  
8 6     6   593 use Dancer2::Core::Types;
  6         15  
  6         64  
9 6     6   93749 use Dancer2::FileUtils qw(path set_file_mode escape_filename);
  6         15  
  6         489  
10 6     6   39 use Fcntl ':flock';
  6         16  
  6         963  
11 6     6   5176 use File::Copy ();
  6         27545  
  6         5255  
12              
13             #--------------------------------------------------------------------------#
14             # Required by classes consuming this role
15             #--------------------------------------------------------------------------#
16              
17             requires '_suffix'; # '.yml', '.json', etc.
18             requires '_thaw_from_handle'; # given handle, return session 'data' field
19             requires '_freeze_to_handle'; # given handle and data, serialize it
20              
21              
22             #--------------------------------------------------------------------------#
23             # Attributes and methods
24             #--------------------------------------------------------------------------#
25              
26             has session_dir => (
27             is => 'ro',
28             isa => Str,
29             default => sub { path( '.', 'sessions' ) },
30             );
31              
32             sub BUILD {
33 4     4 0 430 my $self = shift;
34              
35 4 100       284 if ( !-d $self->session_dir ) {
36 1 50       276 mkdir $self->session_dir
37             or croak "Unable to create session dir : "
38             . $self->session_dir . ' : '
39             . $!;
40             }
41             }
42              
43             sub _sessions {
44 0     0   0 my ($self) = @_;
45 0         0 my $sessions = [];
46              
47 0 0       0 opendir( my $dh, $self->session_dir )
48             or croak "Unable to open directory " . $self->session_dir . " : $!";
49              
50 0         0 my $suffix = $self->_suffix;
51              
52 0         0 while ( my $file = readdir($dh) ) {
53 0 0 0     0 next if $file eq '.' || $file eq '..';
54 0 0       0 if ( $file =~ /(\w+)\Q$suffix\E/ ) {
55 0         0 push @{$sessions}, $1;
  0         0  
56             }
57             }
58 0         0 closedir($dh);
59              
60 0         0 return $sessions;
61             }
62              
63             sub _retrieve {
64 17     17   93 my ( $self, $id ) = @_;
65 17         162 my $session_file = path( $self->session_dir, escape_filename($id) . $self->_suffix );
66              
67 17 100       820 croak "Invalid session ID: $id" unless -f $session_file;
68              
69 16 50       725 open my $fh, '+<', $session_file or die "Can't open '$session_file': $!\n";
70 16 50       168 flock $fh, LOCK_SH or die "Can't lock file '$session_file': $!\n";
71 16         99 my $data = $self->_thaw_from_handle($fh);
72 16 50       58894 close $fh or die "Can't close '$session_file': $!\n";
73              
74 16         182 return $data;
75             }
76              
77             sub _change_id {
78 1     1   4 my ($self, $old_id, $new_id) = @_;
79              
80 1         10 my $old_path =
81             path($self->session_dir, escape_filename($old_id) . $self->_suffix);
82              
83 1 50       34 return if !-f $old_path;
84              
85 1         8 my $new_path =
86             path($self->session_dir, escape_filename($new_id) . $self->_suffix);
87              
88 1         7 File::Copy::move($old_path, $new_path);
89             }
90              
91             sub _destroy {
92 5     5   38 my ( $self, $id ) = @_;
93 5         34 my $session_file = path( $self->session_dir, escape_filename($id) . $self->_suffix );
94 5 50       145 return if !-f $session_file;
95              
96 5         729 unlink $session_file;
97             }
98              
99             sub _flush {
100 21     21   401 my ( $self, $id, $data ) = @_;
101 21         177 my $session_file = path( $self->session_dir, escape_filename($id) . $self->_suffix );
102              
103 21 50       3556 open my $fh, '>', $session_file or die "Can't open '$session_file': $!\n";
104 21 50       336 flock $fh, LOCK_EX or die "Can't lock file '$session_file': $!\n";
105 21 50       160 seek $fh, 0, 0 or die "Can't seek in file '$session_file': $!\n";
106 21 50       793 truncate $fh, 0 or die "Can't truncate file '$session_file': $!\n";
107 21         141 set_file_mode($fh);
108 21         158 $self->_freeze_to_handle( $fh, $data );
109 21 50       3313 close $fh or die "Can't close '$session_file': $!\n";
110              
111 21         236 return $data;
112             }
113              
114             1;
115              
116             __END__