Last active
December 21, 2015 12:29
-
-
Save dolmen/6306377 to your computer and use it in GitHub Desktop.
Hi-jacking File::Fetch API for AnyEvent-backed parallel file download
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use 5.014; | |
use strict; | |
use warnings; | |
{ | |
package File::Fetch::AnyEvent::HTTP; | |
use parent 'File::Fetch'; | |
use AnyEvent::HTTP; | |
# | |
# Returns an AnyEvent condvar that will be triggered when the download is done. | |
# | |
# Get data in $content: | |
# $ff->fetch(to => \my $content)->recv; | |
# Get data save as a file in $dir: | |
# $file = $ff->fetch(to => $dir)->recv; | |
# | |
sub fetch | |
{ | |
my ($self, $TO, $to) = @_; | |
die if @_ > 2 && ($TO ne 'to' || !defined $to); | |
my $cv = AE::cv; | |
# Called as $ff->fetch(to => \my $content)->recv; | |
if (ref $to) { | |
http_get $self->uri, | |
on_body => sub { | |
$$to .= $_[0]; | |
return 1 | |
}, | |
sub { | |
$cv->send | |
}; | |
return $cv | |
} | |
$to = Cwd::cwd() unless defined $to; | |
unless (-d $to) { | |
mkpath($to) or die; | |
} | |
my $file = File::Spec->catfile($to, $self->output_file); | |
open my $f, '>:raw', $file or die; | |
# TODO The returned cv should also be used to track cancellation | |
# (if the caller drops the $cv, the request should be properly | |
# cancelled) | |
# TODO Handle redirects transparently | |
http_get $self->uri, | |
on_body => sub { | |
print $f $_[0]; | |
return 1 | |
}, | |
sub { | |
close $f; | |
$cv->send($file); | |
}; | |
return $cv | |
} | |
} | |
use URI; | |
# Get the CSS file | |
my $css_uri = 'http://glyphicons.com/wp-content/themes/glyphicons/sk/public/css/style-new.css?ver=1.0'; | |
my $ff = File::Fetch::AnyEvent::HTTP->new(uri => $css_uri); | |
my $cv = $ff->fetch(); | |
my $css_file = $cv->recv; | |
my $css = do { local $/; open my $f, '<', $css_file or die; <$f> }; | |
$cv->recv; | |
die unless $css; | |
# Extract the fonts URLs from the CSS content | |
my @urls = $css =~ m< | |
url\( | |
'? | |
( | |
.+? | |
/fonts/ | |
[^')]+ | |
# \. (?: eot | woff | ttf ) | |
) | |
(?: \# .*? )? | |
'? | |
\) | |
>gx; | |
# cleanup | |
undef $css; | |
$cv = AE::cv; | |
# Fetch the font files | |
my %fetching; | |
foreach my $rel_url (@urls) { | |
my $url = URI->new_abs($rel_url, $css_uri); | |
$url->fragment(undef); | |
$ff = File::Fetch::AnyEvent::HTTP->new(uri => $url); | |
my $output_file = $ff->output_file; | |
say "$url => ", $ff->output_file; | |
if (exists $fetching{$output_file}) { | |
warn "$output_file duplicate!\n"; | |
next | |
} | |
$cv->begin; | |
my $file_cv = $ff->fetch(); | |
$fetching{$output_file} = $file_cv; | |
$file_cv->cb(sub { | |
say "$output_file: done."; | |
delete $fetching{$output_file}; | |
$cv->end; | |
}); | |
} | |
# Start the event loop, and the downloads | |
$cv->recv; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment