File Coverage

blib/lib/IPC/Manager/Client/MessageFiles.pm
Criterion Covered Total %
statement 95 107 88.7
branch 28 50 56.0
condition 4 9 44.4
subroutine 19 21 90.4
pod 6 13 46.1
total 152 200 76.0


line stmt bran cond sub pod time code
1             package IPC::Manager::Client::MessageFiles;
2 1     1   5 use strict;
  1         1  
  1         31  
3 1     1   3 use warnings;
  1         1  
  1         49  
4              
5             our $VERSION = '0.000005';
6              
7 1     1   3 use Carp qw/croak confess/;
  1         2  
  1         63  
8 1     1   4 use File::Spec;
  1         1  
  1         120  
9              
10             BEGIN {
11 1 0   1   3 if (eval { require Linux::Inotify2; require IO::Select; Linux::Inotify2->can('fh') ? 1 : 0 }) {
  1 50       226  
  0         0  
  0         0  
12 0         0 *USE_INOTIFY = sub() { 1 };
13             }
14             else {
15 1         28 *USE_INOTIFY = sub() { 0 };
16             }
17             }
18              
19 1     1   3 use parent 'IPC::Manager::Base::FS';
  1         2  
  1         7  
20 1         5 use Object::HashBase qw{
21             +dir_handle
22             +inotify
23              
24             +pend_count
25             +ready_count
26 1     1   71 };
  1         1  
27              
28 29     29 1 403 sub check_path { -d $_[1] }
29 4 50   4 1 296 sub make_path { mkdir($_[1]) or die "Could not make dir '$_[1]': $!" }
30 4     4 1 8 sub path_type { 'subdir' }
31              
32             sub init {
33 4     4 0 96 my $self = shift;
34              
35 4         16 $self->SUPER::init();
36              
37 4         9 $self->{+PEND_COUNT} = 0;
38 4         7 $self->{+READY_COUNT} = 0;
39              
40 4         8 return unless USE_INOTIFY;
41             }
42              
43 0     0 0 0 sub handles_for_select { $_[0]->inotify->fh }
44              
45             sub inotify {
46 0     0 0 0 my $self = shift;
47 0         0 croak "Not Implemented (Or you are missing one of: Linux::Inotify2, IO::Select)" unless USE_INOTIFY();
48              
49 0 0       0 return $self->{+INOTIFY} if $self->{+INOTIFY};
50              
51 0         0 my $i = Linux::Inotify2->new;
52 0         0 $i->watch($self->path, Linux::Inotify2::IN_CREATE());
53              
54 0         0 return $self->{+INOTIFY} = $i;
55             }
56              
57             sub pre_disconnect_hook {
58 4     4 1 6 my $self = shift;
59              
60 4         60 my $new_path = File::Spec->catfile($self->{+ROUTE}, "_" . $self->{+ID});
61 4 50       16 rename($self->path, $new_path) or die "Cannot rename directory: $!";
62 4         21 $self->{+PATH} = $new_path;
63             }
64              
65             sub dir_handle {
66 24     24 0 26 my $self = shift;
67 24         44 $self->pid_check;
68 24   66     52 my $out = $self->{+DIR_HANDLE} //= do {
69 4 50       18 opendir(my $dh, $self->path) or die "Could not open dir: $!";
70 4         14 $dh;
71             };
72              
73 24         97 rewinddir($out);
74              
75 24         539 return $out;
76             }
77              
78             sub pending_messages {
79 6     6 0 10 my $self = shift;
80 6 50       15 return 1 if $self->{+PEND_COUNT};
81 6 50       16 return $self->message_files('pend') ? 1 : 0;
82             }
83              
84             sub ready_messages {
85 6     6 0 9 my $self = shift;
86 6 100       19 return 1 if $self->{+READY_COUNT};
87 3 50       16 return 1 if $self->have_resume_file;
88 3 50       9 return $self->message_files('ready') ? 1 : 0;
89             }
90              
91             sub message_files {
92 24     24 0 55 my $self = shift;
93 24         66 $self->pid_check;
94 24         39 my ($ext) = @_;
95              
96 24         25 return undef if USE_INOTIFY && !$self->select->can_read(0);
97              
98 24         34 my (@pend, @ready);
99 24         45 for my $file (readdir($self->dir_handle)) {
100 65 100       189 if ($file =~ m/\.ready$/) {
    50          
101 17         36 push @ready => $file;
102             }
103             elsif ($file =~ m/\.pend$/) {
104 0         0 push @pend => $file;
105             }
106             }
107              
108 24         60 $self->{+READY_COUNT} = @ready;
109 24         46 $self->{+PEND_COUNT} = @pend;
110              
111 24 100       113 return @ready ? \@ready : undef if $ext eq 'ready';
    100          
112 6 50       47 return @pend ? \@pend : undef if $ext eq 'pend';
    50          
113              
114 0         0 return undef;
115             }
116              
117             sub get_messages {
118 15     15 1 6970 my $self = shift;
119 15         25 my ($ext) = @_;
120              
121 15         19 my @out;
122              
123 15 100       60 my $ready = $self->message_files('ready') or return;
124              
125 10         32 for my $msg (@$ready) {
126 13         37 my $full = File::Spec->catfile($self->path, $msg);
127 13 50       487 open(my $fh, '<', $full) or die "Could not open file '$full': $!";
128 13         24 my $content = do { local $/; <$fh> };
  13         51  
  13         327  
129 13         87 close($full);
130 13 50       576 unlink($full) or die "Could not unlink file '$full': $!";
131              
132 13         103 my $msg = IPC::Manager::Message->new($self->{+SERIALIZER}->deserialize($content));
133 13         102 push @out => $msg;
134              
135 13         887 $self->{+STATS}->{read}->{$msg->{from}}++;
136             }
137              
138 10         62 push @out => $self->read_resume_file;
139              
140 10         65 return sort { $a->stamp <=> $b->stamp } @out;
  3         32  
141             }
142              
143             sub _write_message_file {
144 13     13   13 my $self = shift;
145 13         20 my ($msg, $peer) = @_;
146              
147 13 50 33     42 $peer //= $msg->to or croak "Message has no peer";
148              
149 13 50       30 my $msg_dir = $self->peer_exists($peer) or croak "Client does not exist";
150 13         87 my $msg_file = File::Spec->catfile($msg_dir, $msg->id);
151              
152 13         22 my $pend = "$msg_file.pend";
153 13         17 my $ready = "$msg_file.ready";
154              
155 13 50 33     697 confess "Message file '$msg_file' already exists" if -e $pend || -e $ready;
156              
157 13 50       1136 open(my $fh, '>', $pend) or die "Could not open '$pend': $!";
158              
159 13         107 print $fh $self->{+SERIALIZER}->serialize($msg);
160              
161 13         445 close($fh);
162              
163 13 50       762 rename($pend, $ready) or die "Could not rename file: $!";
164              
165 13         57 $self->{+STATS}->{sent}->{$msg->{to}}++;
166 13         97 return $ready;
167             }
168              
169             sub send_message {
170 13     13 1 692 my $self = shift;
171 13         34 my $msg = $self->build_message(@_);
172 13         82 $self->pid_check;
173 13         25 $self->_write_message_file($msg);
174             }
175              
176             1;
177              
178             __END__