File Coverage

lib/App/MtAws/ChildWorker.pm
Criterion Covered Total %
statement 43 135 31.8
branch 6 74 8.1
condition n/a
subroutine 11 14 78.5
pod 0 4 0.0
total 60 227 26.4


line stmt bran cond sub pod time code
1             # mt-aws-glacier - Amazon Glacier sync client
2             # Copyright (C) 2012-2014 Victor Efimov
3             # http://mt-aws.com (also http://vs-dev.com) vs@vs-dev.com
4             # License: GPLv3
5             #
6             # This file is part of "mt-aws-glacier"
7             #
8             # mt-aws-glacier is free software: you can redistribute it and/or modify
9             # it under the terms of the GNU General Public License as published by
10             # the Free Software Foundation, either version 3 of the License, or
11             # (at your option) any later version.
12             #
13             # mt-aws-glacier is distributed in the hope that it will be useful,
14             # but WITHOUT ANY WARRANTY; without even the implied warranty of
15             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16             # GNU General Public License for more details.
17             #
18             # You should have received a copy of the GNU General Public License
19             # along with this program. If not, see <http://www.gnu.org/licenses/>.
20              
21             package App::MtAws::ChildWorker;
22              
23             our $VERSION = '1.114_2';
24              
25 18     18   8023 use App::MtAws::LineProtocol;
  18         35  
  18         1183  
26 18     18   8030 use App::MtAws::GlacierRequest;
  18         47  
  18         708  
27 18     18   120 use App::MtAws::Utils;
  18         32  
  18         2617  
28 18     18   120 use App::MtAws::Exceptions;
  18         19  
  18         1187  
29 18     18   94 use strict;
  18         28  
  18         420  
30 18     18   77 use warnings;
  18         27  
  18         432  
31 18     18   78 use utf8;
  18         27  
  18         101  
32 18     18   370 use Carp;
  18         21  
  18         1662  
33 18     18   2436 use IO::Select;
  18         6123  
  18         583  
34 18     18   65 use POSIX;
  18         19  
  18         128  
35              
36             sub new
37             {
38 0     0 0 0 my ($class, %args) = @_;
39 0         0 my $self = \%args;
40 0 0       0 $self->{fromchild}||die;
41 0 0       0 $self->{tochild}||die;
42 0 0       0 $self->{options}||die;
43 0         0 bless $self, $class;
44 0         0 return $self;
45             }
46              
47             sub process
48             {
49 0     0 0 0 my ($self) = @_;
50              
51 0         0 my $tochild = $self->{tochild};
52 0         0 my $fromchild = $self->{fromchild};
53 0         0 while (1) {
54 0         0 my ($remote_pid, $action, $taskid, $data, $attachmentref) = get_data($tochild);
55 0 0       0 $remote_pid or comm_error(); # we exit() if eof or socket error. we don't distinct
56 0         0 my ($result, $result_attachmentref, $console_out) = $self->process_task($action, $data, $attachmentref);
57 0         0 $result->{console_out}=$console_out;
58 0 0       0 send_data($fromchild, 'response', $taskid, $result, $result_attachmentref) or comm_error();
59             };
60             # unreachable
61             }
62              
63             sub process_task
64             {
65 1     1 0 827 my ($self, $action, $data, $attachmentref) = @_;
66 1         2 my ($result, $result_attachmentref) = (undef, undef);
67              
68 1         1 my $console_out = undef;
69 1 50       11 if ($action eq 'create_upload') {
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
70             # TODO: partsize confusing, need use another name for option partsize. partsize Amazon Upload partsize vs Download 'Range' partsize
71 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
72 0         0 my $uploadid = $req->create_multipart_upload($data->{partsize}, $data->{relfilename}, $data->{mtime});
73 0 0       0 confess unless $uploadid;
74 0         0 $result = { upload_id => $uploadid };
75 0         0 $console_out = "Created an upload_id $uploadid";
76             } elsif ($action eq "upload_part") {
77 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
78 0         0 my $r = $req->upload_part($data->{upload_id}, $attachmentref, $data->{start}, $data->{part_final_hash});
79 0 0       0 confess "upload_part failed" unless $r;
80 0         0 $result = { uploaded => $data->{start} } ;
81 0         0 $console_out = "Uploaded part for $data->{relfilename} at offset [$data->{start}]";
82             } elsif ($action eq 'finish_upload') {
83             # TODO: move vault to task, not to options!
84 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
85 0         0 my $archive_id = $req->finish_multipart_upload($data->{upload_id}, $data->{filesize}, $data->{final_hash});
86 0 0       0 confess "finish_upload failed" unless $archive_id;
87             $result = {
88             final_hash => $data->{final_hash},
89             archive_id => $archive_id,
90             journal_entry => {
91             type=> 'CREATED',
92             'time' => $req->{last_request_time},
93             archive_id => $archive_id,
94             size => $data->{filesize},
95             mtime => $data->{mtime},
96             treehash => $data->{final_hash},
97             relfilename => $data->{relfilename}
98             },
99 0         0 };
100 0         0 $console_out = "Finished $data->{relfilename} hash [$data->{final_hash}] archive_id [$archive_id]";
101             } elsif ($action eq 'delete_archive') {
102 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
103 0         0 my $r = $req->delete_archive($data->{archive_id});
104 0 0       0 confess "delete_archive failed" unless $r;
105             $result = {
106             journal_entry => {
107             type=> 'DELETED',
108             'time' => $req->{last_request_time},
109             archive_id => $data->{archive_id},
110             relfilename => $data->{relfilename}
111             }
112 0         0 };
113 0         0 $console_out = "Deleted $data->{relfilename} archive_id [$data->{archive_id}]";
114             } elsif ($action eq 'retrieval_download_job') {
115 1         9 my $req = App::MtAws::GlacierRequest->new($self->{options});
116              
117 1         9 my $i_tmp = App::MtAws::IntermediateFile->new(target_file => $data->{filename}, mtime => $data->{mtime});
118 1         4 my $tempfile = $i_tmp->tempfilename;
119              
120 1         7 my $r = $req->retrieval_download_job($data->{jobid}, $data->{relfilename}, $tempfile, $data->{size}, $data->{treehash});
121              
122 1 50       3 confess "retrieval_download_job failed" unless $r;
123              
124 1         3 $i_tmp->make_permanent;
125              
126 1         3 $result = { response => $r };
127 1         6 $console_out = "Downloaded archive $data->{filename}";
128             } elsif ($action eq 'segment_download_job') {
129 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
130 0         0 my $r = $req->segment_download_job($data->{jobid}, $data->{tempfile}, $data->{filename}, $data->{position}, $data->{download_size});
131 0 0       0 confess "segment_download_job failed" unless $r;
132 0         0 $result = { response => $r };
133 0         0 $console_out = "Downloaded part of archive $data->{filename} at offset $data->{position}, size $data->{download_size}";
134             } elsif ($action eq 'inventory_download_job') {
135 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
136 0         0 my ($r, $inventory_type) = $req->retrieval_download_to_memory($data->{job_id});
137 0 0       0 confess "inventory_download_job failed" unless $r;
138 0         0 $result = { response => !! $r, inventory_type => $inventory_type };
139 0         0 $result_attachmentref = \$r;
140 0 0       0 $console_out = "Downloaded inventory in ".($inventory_type eq INVENTORY_TYPE_JSON ? "JSON" : "CSV")." format";
141             } elsif ($action eq 'retrieve_archive') {
142 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
143 0         0 my $r = $req->retrieve_archive( $data->{archive_id});
144 0 0       0 return "retrieve_archive failed" unless $r;
145             $result = {
146             journal_entry => {
147             type=> 'RETRIEVE_JOB',
148             'time' => $req->{last_request_time},
149             archive_id => $data->{archive_id},
150 0         0 job_id => $r,
151             }
152             };
153 0         0 $console_out = "Retrieved Archive $data->{archive_id}";
154             } elsif ($action eq 'retrieval_fetch_job') {
155 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
156 0         0 my $r = $req->retrieval_fetch_job($data->{marker});
157 0 0       0 confess unless $r;
158 0         0 $result = { response => $r };
159 0         0 $console_out = "Retrieved Job List";
160             } elsif ($action eq 'inventory_fetch_job') {
161 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
162 0         0 my $r = $req->retrieval_fetch_job($data->{marker});
163 0 0       0 confess unless $r;
164 0         0 $result = { response => $r };
165 0         0 $console_out = "Fetched job list for inventory retrieval";
166             } elsif ($action eq 'retrieve_inventory_job') {
167 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
168 0         0 my $r = $req->retrieve_inventory($data->{format});
169 0 0       0 confess unless $r;
170 0         0 $result = { job_id => $r };
171 0         0 $console_out = "Retrieved Inventory, job id $r";
172             } elsif ($action eq 'create_vault_job') {
173 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
174 0         0 my $r = $req->create_vault($data->{name});
175 0 0       0 confess unless $r;
176 0         0 $result = { };
177 0         0 $console_out = "Created vault $data->{name}";
178             } elsif ($action eq 'delete_vault_job') {
179 0         0 my $req = App::MtAws::GlacierRequest->new($self->{options});
180 0         0 my $r = $req->delete_vault($data->{name});
181 0 0       0 confess unless $r;
182 0         0 $result = { };
183 0         0 $console_out = "Deleted vault $data->{name}";
184             } elsif ($action eq 'verify_file') {
185 0         0 my $th = App::MtAws::TreeHash->new();
186 0         0 my $binaryfilename = binaryfilename $data->{filename};
187             die exception file_is_zero => "File size is zero (and it was not when we read directory listing). Filename: %string filename%",
188             filename => $data->{filename}
189 0 0       0 unless -s $binaryfilename;
190              
191             open_file(my $F, $data->{filename}, mode => '<', binary => 1) or
192             die exception upload_file_open_error => "Unable to open task file %string filename% for reading, errno=%errno%",
193 0 0       0 filename => $data->{filename}, 'ERRNO'; # TODO: test
194              
195 0         0 $th->eat_file($F);
196 0 0       0 close $F or confess;
197 0         0 $th->calc_tree();
198 0         0 my $treehash = $th->get_final_hash();
199              
200 0 0       0 if ($treehash eq $data->{treehash}) {
201 0         0 $result = { match => 1 };
202 0         0 $console_out = "Checked treehash for $data->{filename} - MATCH";
203             } else {
204 0         0 $result = { match => 0 };
205 0         0 $console_out = "Checked treehash for $data->{filename} - DOES NOT MATCH";
206             }
207             } else {
208 0         0 die $action;
209             }
210 1         3 return ($result, $result_attachmentref, $console_out);
211             }
212              
213             sub comm_error
214             {
215             # error message useless here
216 0     0 0   exit(1);
217             }
218              
219             1;