一番近い CPAN ミラーを検出するスクリプトを書いた

READ IN ENGLISH

CPAN モジュールをインストールするときに、ダウンロード速度が気になったので、ミラーサイトから一番近いサイトをピックアップするスクリプトを書いてみました。

CPAN から、MIRRORED.BY を取ってきて、dst_http に指定されているホスト全てに、5回 ping を飛ばして、平均スピードが速かった上位 5 サイトの URI を出力します。o conf ラインも出力するので、cpan シェルにそのままコピペで設定できます。o conf commit を忘れないように注意。

ftp を使いたい人は、dst_http を dst_ftp に変更してください。

ちなみに、EC2 の us-east-1c からは、以下のサイトがランクインしました。

2.311 ms : cpan-du.viaverio.com
7.732 ms : ftp.fxcorporate.com
8.229 ms : mirrors.24-7-solutions.net
8.912 ms : mirror.datapipe.net
9.388 ms : mirror.cc.columbia.edu
o conf urllist push http://cpan-du.viaverio.com/
o conf urllist push http://ftp.fxcorporate.com/CPAN/
o conf urllist push http://mirrors.24-7-solutions.net/pub/CPAN/
o conf urllist push http://mirror.datapipe.net/CPAN/
o conf urllist push http://mirror.cc.columbia.edu/pub/software/cpan/
o conf commit

以下ソースです。

#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
use LWP::Simple;

my $mirrored_by = 'http://www.cpan.org/pub/CPAN/MIRRORED.BY';

my $content = get( $mirrored_by );
die "Couldn't get MIRRORED.BY" unless defined $content;

my $data;
for my $uri ( $content =~ /^\s+dst_http\s+=\s+"(.+?)"/gm ) {

    my $host = URI->new( $uri )->host;
    printf "%-40s\r", $host;

    open2( my $out, undef, qw(ping -nq -c 5 -i 0.2), $host );
    my @res = <$out>;
    $out->close;

    my ( $loss ) = $res[-2] =~ /(\d)% packet loss/o;
    my ( $avg  ) = (split '/', $res[-1])[4];
    next if $loss ne '0';
    next if !$avg;

    $data->{$host} = {
        uri => $uri,
        avg => $avg,
    };
}

my @rank = sort { $data->{$a}{'avg'} <=> $data->{$b}{'avg'} } keys %$data;

my ( $rank, $conf ) = ('') x 2;
for my $host (@rank[0..4]) {
    $rank .= sprintf "%s ms : %s\n", $data->{$host}{'avg'}, $host;
    $conf .= sprintf "o conf urllist push %s\n", $data->{$host}{'uri'};
}
print " " x 50, "\n";
print $rank, $conf;
print "o conf commit\n";