App-ManiacDownloader
view release on metacpan or search on metacpan
lib/App/ManiacDownloader.pm view on Meta::CPAN
# We do these to make sure the cancellation guard does not get
# preserved because it's in the context of the closures.
my $on_body = sub {
my ( $active_seq, $data, $hdr ) = @_;
# Stale or wrong connection - probably AnyEvent::FTP::Client after a
# quit.
if ( ( !$r->_is_right_active_seq($active_seq) ) or ( !$r->is_active ) )
{
return;
}
my $ret = $r->_write_data( \$data );
$self->_downloaded->_add( $ret->{num_written} );
my $cont = $ret->{should_continue};
if ( !$cont )
{
if ($is_ftp)
{
$r->_guard->quit;
}
my $largest_r = max_by { $r->_num_remaining } @{ $self->_ranges };
if ( $largest_r->_num_remaining < $NUM_CONN_BYTES_THRESHOLD )
{
$r->_close;
if (
not $self->_remaining_connections(
$self->_remaining_connections() - 1
)
)
{
$self->_finished_condvar->send;
}
}
else
{
$largest_r->_split_into($r);
$self->_start_connection($idx);
}
}
return $cont;
};
my $final_cb = sub { return; };
my $url = $self->_file->_url;
{
my $active_seq = $r->_get_next_active_seq;
my $seq_on_body = sub { return $on_body->( $active_seq, @_ ); };
if ($is_ftp)
{
my $ftp = AnyEvent::FTP::Client->new( passive => 1 );
$r->_guard($ftp);
$ftp->connect( $url->host, $url->port )->cb(
sub {
$ftp->login( $url->user, $url->password )->cb(
sub {
$ftp->type('I')->cb(
sub {
$ftp->retr( $self->_file->_url_path,
$seq_on_body, restart => $r->_start, );
}
);
}
);
}
);
}
else
{
my $guard = http_get $url,
headers =>
{ 'Range' => sprintf( "bytes=%d-%d", $r->_start, $r->_end - 1 )
},
on_body => $seq_on_body,
$final_cb;
$r->_guard($guard);
$guard = '';
}
}
return;
}
my $MAX_CHECKS = 6;
sub _handle_stats_timer
{
my ($self) = @_;
my ( $num_dloaded, $total_downloaded ) =
$self->_downloaded->_flush_and_report;
my $_ranges = $self->_ranges;
for my $idx ( 0 .. $#$_ranges )
{
my $r = $_ranges->[$idx];
$r->_flush_and_report;
if ( $r->is_active && $r->_increment_check_count($MAX_CHECKS) )
{
$r->_guard('');
$self->_start_connection($idx);
}
}
my $time = AnyEvent->now;
my $last_time = $self->_last_timer_time;
printf "Downloaded %i%% (Currently: %.2fKB/s)\r",
int( $total_downloaded * 100 / $self->_len ),
( $num_dloaded / ( 1024 * ( $time - $last_time ) ) ),
;
STDOUT->flush;
lib/App/ManiacDownloader.pm view on Meta::CPAN
print {$json_out_fh} encode_json( $self->_serialize );
close($json_out_fh);
exit(2);
}
sub run
{
my ( $self, $args ) = @_;
my $num_connections = $DEFAULT_NUM_CONNECTIONS;
my @argv = @{ $args->{argv} };
if (
!GetOptionsFromArray(
\@argv, 'k|num-connections=i' => \$num_connections,
)
)
{
die "Cannot parse argv - $!";
}
my $url_s = shift(@argv)
or die "No url given.";
$self->_file( App::ManiacDownloader::_File->new );
$self->_file->_set_url($url_s);
if ( -e $self->_file->_url_basename )
{
print STDERR
"File appears to have already been downloaded. Quitting.\n";
return;
}
$self->_finished_condvar( scalar( AnyEvent->condvar ) );
if ( -e $self->_file->_resume_info_path )
{
my $record = decode_json( _slurp( $self->_file->_resume_info_path ) );
$self->_len( $record->{_len} );
$self->_downloaded->_my_init( $record->{_bytes_dled} );
$self->_remaining_connections( $record->{_remaining_connections} );
my $ranges_ref = $record->{_ranges};
$self->_init_from_len(
{
ranges => $ranges_ref,
num_connections => scalar(@$ranges_ref),
}
);
}
else
{
my $url = $self->_file->_url;
if ( $self->_file->_is_ftp )
{
my $ftp = AnyEvent::FTP::Client->new( passive => 1 );
$ftp->connect( $url->host, $url->port )->recv;
$ftp->login( $url->user, $url->password )->recv;
$ftp->type('I')->recv;
$ftp->size( $self->_file->_url_path )->cb(
sub {
my $len = shift->recv;
$ftp->quit;
undef($ftp);
return $self->_with_len_and_num_connections( $len,
$num_connections );
}
);
}
else
{
http_head $url, sub {
my ( undef, $headers ) = @_;
my $len = $headers->{'content-length'};
return $self->_with_len_and_num_connections( $len,
$num_connections );
};
}
}
my $signal_handler = sub { $self->_abort_signal_handler(); };
local $SIG{INT} = $signal_handler;
local $SIG{TERM} = $signal_handler;
$self->_finished_condvar->recv;
$self->_stats_timer( undef() );
if ( !$self->_remaining_connections() )
{
rename( $self->_file->_downloading_path(),
$self->_file->_url_basename() );
}
return;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
App::ManiacDownloader - a maniac download accelerator.
=head1 VERSION
version 0.0.13
=head1 SYNOPSIS
# To download with 10 segments
( run in 0.759 second using v1.01-cache-2.11-cpan-ceb78f64989 )