| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Net::Stomp::MooseHelpers::ReadTrace; | 
| 2 |  |  |  |  |  |  | $Net::Stomp::MooseHelpers::ReadTrace::VERSION = '3.0'; | 
| 3 |  |  |  |  |  |  | { | 
| 4 |  |  |  |  |  |  | $Net::Stomp::MooseHelpers::ReadTrace::DIST = 'Net-Stomp-MooseHelpers'; | 
| 5 |  |  |  |  |  |  | } | 
| 6 | 1 |  |  | 1 |  | 155620 | use Moose; | 
|  | 1 |  |  |  |  | 386928 |  | 
|  | 1 |  |  |  |  | 6 |  | 
| 7 | 1 |  |  | 1 |  | 6822 | use MooseX::Types::Path::Class; | 
|  | 1 |  |  |  |  | 105673 |  | 
|  | 1 |  |  |  |  | 6 |  | 
| 8 | 1 |  |  | 1 |  | 1346 | use Net::Stomp::Frame; | 
|  | 1 |  |  |  |  | 3659 |  | 
|  | 1 |  |  |  |  | 6 |  | 
| 9 | 1 |  |  | 1 |  | 46 | use Path::Class; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 54 |  | 
| 10 | 1 |  |  | 1 |  | 5 | use Carp; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 55 |  | 
| 11 |  |  |  |  |  |  | require Net::Stomp::MooseHelpers::TraceStomp; | 
| 12 | 1 |  |  | 1 |  | 5 | use namespace::autoclean; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 16 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | # ABSTRACT: class to read the output of L<Net::Stomp::MooseHelpers::TraceStomp> | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | has trace_basedir => ( | 
| 18 |  |  |  |  |  |  | is => 'rw', | 
| 19 |  |  |  |  |  |  | isa => 'Path::Class::Dir', | 
| 20 |  |  |  |  |  |  | coerce => 1, | 
| 21 |  |  |  |  |  |  | required => 1, | 
| 22 |  |  |  |  |  |  | ); | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | sub read_frame_from_filename { | 
| 26 | 5 |  |  | 5 | 1 | 11 | my ($self,$filename) = @_; | 
| 27 |  |  |  |  |  |  |  | 
| 28 | 5 |  |  |  |  | 20 | my $fh=file($filename)->openr; | 
| 29 | 5 |  |  |  |  | 1266 | binmode $fh; | 
| 30 | 5 |  |  |  |  | 20 | return $self->read_frame_from_fh($fh); | 
| 31 |  |  |  |  |  |  | } | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | sub read_frame_from_fh { | 
| 35 | 5 |  |  | 5 | 1 | 10 | my ($self,$fh) = @_; | 
| 36 |  |  |  |  |  |  |  | 
| 37 | 5 |  |  |  |  | 21 | local $/="\x0A"; | 
| 38 | 5 |  |  |  |  | 107 | my $command=<$fh>; | 
| 39 | 5 | 50 |  |  |  | 19 | return unless $command; | 
| 40 | 5 |  |  |  |  | 12 | chomp $command; | 
| 41 | 5 |  |  |  |  | 9 | my %headers; | 
| 42 | 5 |  |  |  |  | 23 | while (defined(my $header_line=<$fh>)) { | 
| 43 | 17 |  |  |  |  | 30 | chomp $header_line; | 
| 44 | 17 | 100 |  |  |  | 38 | last if $header_line eq ''; | 
| 45 |  |  |  |  |  |  |  | 
| 46 | 12 |  |  |  |  | 38 | my ($key,$value) = split ':',$header_line,2; | 
| 47 | 12 |  |  |  |  | 42 | $headers{$key}=$value; | 
| 48 |  |  |  |  |  |  | } | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 5 |  |  |  |  | 17 | local $/=undef; | 
| 51 |  |  |  |  |  |  |  | 
| 52 | 5 |  |  |  |  | 56 | my $body=<$fh>; | 
| 53 |  |  |  |  |  |  |  | 
| 54 | 5 | 50 |  |  |  | 17 | return unless $body; | 
| 55 | 5 | 50 |  |  |  | 32 | return unless $body =~ s{\x00$}{}; # 0 marks the end of the frame | 
| 56 |  |  |  |  |  |  |  | 
| 57 | 5 |  |  |  |  | 56 | return Net::Stomp::Frame->new({ | 
| 58 |  |  |  |  |  |  | command => $command, | 
| 59 |  |  |  |  |  |  | headers => \%headers, | 
| 60 |  |  |  |  |  |  | body => $body, | 
| 61 |  |  |  |  |  |  | }); | 
| 62 |  |  |  |  |  |  | } | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | sub trace_subdir_for_destination { | 
| 66 | 5 |  |  | 5 | 1 | 18 | my ($self,$destination) = @_; | 
| 67 |  |  |  |  |  |  |  | 
| 68 | 5 | 50 |  |  |  | 18 | if (@_==1) { | 
| 69 | 5 |  |  |  |  | 210 | return $self->trace_basedir; | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 0 | 0 |  |  |  | 0 | confess "You must pass a defined, non-empty destination" | 
| 73 |  |  |  |  |  |  | if !length($destination); | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 0 |  |  |  |  | 0 | return $self->trace_basedir->subdir( | 
| 76 |  |  |  |  |  |  | Net::Stomp::MooseHelpers::TracerRole-> | 
| 77 |  |  |  |  |  |  | _dirname_from_destination($destination) | 
| 78 |  |  |  |  |  |  | ); | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | sub sorted_filenames { | 
| 83 | 3 |  |  | 3 | 1 | 5 | my $self=shift; | 
| 84 |  |  |  |  |  |  |  | 
| 85 | 3 |  |  |  |  | 11 | my $dir = $self->trace_subdir_for_destination(@_); | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 3 | 50 |  |  |  | 23 | return unless -e $dir; | 
| 88 |  |  |  |  |  |  |  | 
| 89 | 3 |  |  |  |  | 149 | my @files; | 
| 90 |  |  |  |  |  |  | $dir->recurse( | 
| 91 |  |  |  |  |  |  | callback=>sub{ | 
| 92 | 14 |  |  | 14 |  | 3420 | my ($f) = @_; | 
| 93 | 14 | 100 |  |  |  | 29 | return if $f->is_dir; | 
| 94 | 5 | 50 |  |  |  | 27 | return unless $f->basename =~ /^\d+\.\d+-\w+-/; | 
| 95 | 5 |  |  |  |  | 40 | push @files,$f; | 
| 96 |  |  |  |  |  |  | }, | 
| 97 | 3 |  |  |  |  | 34 | ); | 
| 98 | 3 |  |  |  |  | 31 | @files = sort { $a->basename cmp $b->basename } @files; | 
|  | 3 |  |  |  |  | 27 |  | 
| 99 |  |  |  |  |  |  |  | 
| 100 | 3 |  |  |  |  | 13 | return @files; | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | sub clear_destination { | 
| 105 | 2 |  |  | 2 | 1 | 28835 | my $self=shift; | 
| 106 |  |  |  |  |  |  |  | 
| 107 | 2 |  |  |  |  | 11 | my $dir = $self->trace_subdir_for_destination(@_); | 
| 108 |  |  |  |  |  |  |  | 
| 109 | 2 |  |  |  |  | 20 | $dir->rmtree({keep_root=>1});$dir->mkpath; | 
|  | 2 |  |  |  |  | 1383 |  | 
| 110 |  |  |  |  |  |  |  | 
| 111 | 2 |  |  |  |  | 112 | return; | 
| 112 |  |  |  |  |  |  | } | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | sub sorted_frames { | 
| 116 | 3 |  |  | 3 | 1 | 8 | my $self=shift; | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | return map { | 
| 119 | 3 |  |  |  |  | 14 | $self->read_frame_from_filename($_) | 
|  | 5 |  |  |  |  | 125 |  | 
| 120 |  |  |  |  |  |  | } $self->sorted_filenames(@_); | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | 1; | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | __END__ | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | =pod | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | =encoding UTF-8 | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | =head1 NAME | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | Net::Stomp::MooseHelpers::ReadTrace - class to read the output of L<Net::Stomp::MooseHelpers::TraceStomp> | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | =head1 VERSION | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | version 3.0 | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | my $reader = Net::Stomp::MooseHelpers::ReadTrace->new({ | 
| 142 |  |  |  |  |  |  | trace_basedir => '/tmp/mq', | 
| 143 |  |  |  |  |  |  | }); | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | my @frames = $reader->sorted_frames('/queue/somewhere'); | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | L<Net::Stomp::MooseHelpers::TraceStomp> and | 
| 150 |  |  |  |  |  |  | L<Net::Stomp::MooseHelpers::TraceOnly> write STOMP frames to | 
| 151 |  |  |  |  |  |  | disk. This class helps you read them back. | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | =head1 ATTRIBUTES | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | =head2 C<trace_basedir> | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | The directory from which frames will be read. Accepts strings and | 
| 158 |  |  |  |  |  |  | L<Path::Class::Dir> objects. | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | =head1 METHODS | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | =head2 C<read_frame_from_filename> | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | my $stomp_frame = $reader->read_frame_from_filename('/a/path'); | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | Given a filename (I<unrelated> to L</trace_basedir>), returns a | 
| 167 |  |  |  |  |  |  | L<Net::Stomp::Frame> object parsed from it, using | 
| 168 |  |  |  |  |  |  | L</read_frame_from_fh>. | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | =head2 C<read_frame_from_fh> | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | my $stomp_frame = $reader->read_frame_from_fh($fh); | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | Given a filehandle (C<binmode> it first!), returns a | 
| 175 |  |  |  |  |  |  | L<Net::Stomp::Frame> object parsed from it. If the filehandle contains | 
| 176 |  |  |  |  |  |  | more than one frame, reads the first one and leaves the read position | 
| 177 |  |  |  |  |  |  | just after it. | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | If the file was not a dumped STOMP frame, this function will probably | 
| 180 |  |  |  |  |  |  | return nothing; if it looked enough like a STOMP frame, you'll get | 
| 181 |  |  |  |  |  |  | back whatever could be parsed. | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | =head2 C<trace_subdir_for_destination> | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | my $dir = $reader->trace_subdir_for_destination($destination); | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | Returns a L<Path::Class::Dir> object pointing at the (possibly | 
| 188 |  |  |  |  |  |  | non-existent) directory used to store frames for the given | 
| 189 |  |  |  |  |  |  | destination. | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | C<< ->trace_subdir_for_destination() >> is the same as C<< | 
| 192 |  |  |  |  |  |  | ->trace_basedir >>. | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | Passing an explicit C<undef> or an empty string will throw an | 
| 195 |  |  |  |  |  |  | exception, see L</sorted_filenames> and L</clear_destination> for the | 
| 196 |  |  |  |  |  |  | reason. | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | =head2 C<sorted_filenames> | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | my @names = $reader->sorted_filenames(); | 
| 201 |  |  |  |  |  |  | my @names = $reader->sorted_filenames($destination); | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | Given a destination (C</queue/something> or similar), returns all | 
| 204 |  |  |  |  |  |  | frame dump filenames found under the corresponding dump directory | 
| 205 |  |  |  |  |  |  | under L</trace_basedir>, sorted by filename (that is, by timestamp). | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | If you don't specify a destination, all filenames from all | 
| 208 |  |  |  |  |  |  | destinations will be returned. Passing an explicit C<undef> or an | 
| 209 |  |  |  |  |  |  | empty string will throw an exception, to save you when you try doing | 
| 210 |  |  |  |  |  |  | things like: | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | my $dest = get_something_from_config; | 
| 213 |  |  |  |  |  |  | my @names = $reader->sorted_filenames($dest); | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | and end up getting way more items than you thought. | 
| 216 |  |  |  |  |  |  |  | 
| 217 |  |  |  |  |  |  | =head2 C<clear_destination> | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | $reader->clear_destination(); | 
| 220 |  |  |  |  |  |  | $reader->clear_destination($destination); | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | Given a destination (C</queue/something> or similar), removes all | 
| 223 |  |  |  |  |  |  | stored frames for it. | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | If you don't specify a destination, all frames for all destinations | 
| 226 |  |  |  |  |  |  | will be removed. Passing an explicit C<undef> or an empty string will | 
| 227 |  |  |  |  |  |  | throw an exception, to save you when you try doing things like: | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | my $dest = get_something_from_config; | 
| 230 |  |  |  |  |  |  | $reader->clear_destination($dest); | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | and end up deleting way more than you thought. | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | =head2 C<sorted_frames> | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | my @frames = $reader->sorted_frames(); | 
| 237 |  |  |  |  |  |  | my @frames = $reader->sorted_frames($destination); | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | Same as L</sorted_filenames>, but returns the parsed frames instead of | 
| 240 |  |  |  |  |  |  | the filenames. | 
| 241 |  |  |  |  |  |  |  | 
| 242 |  |  |  |  |  |  | =head1 AUTHOR | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | Gianni Ceccarelli <gianni.ceccarelli@net-a-porter.com> | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | This software is copyright (c) 2014 by Net-a-porter.com. | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | This is free software; you can redistribute it and/or modify it under | 
| 251 |  |  |  |  |  |  | the same terms as the Perl 5 programming language system itself. | 
| 252 |  |  |  |  |  |  |  | 
| 253 |  |  |  |  |  |  | =cut |