summaryrefslogtreecommitdiffstats
path: root/perl-install/mirror.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/mirror.pm')
-rw-r--r--perl-install/mirror.pm159
1 files changed, 110 insertions, 49 deletions
diff --git a/perl-install/mirror.pm b/perl-install/mirror.pm
index f0a54f4d1..11d55f06b 100644
--- a/perl-install/mirror.pm
+++ b/perl-install/mirror.pm
@@ -1,4 +1,4 @@
-package mirror; # $Id: mirror.pm 269985 2010-06-09 22:02:57Z herton $
+package mirror;
use diagnostics;
use strict;
@@ -7,46 +7,33 @@ use feature 'state';
use common;
use log;
-my %land2tzs = (
- N_("Australia") => [ 'Australia/Sydney' ],
- N_("Austria") => [ 'Europe/Vienna', 'Europe/Brussels', 'Europe/Berlin' ],
- N_("Belgium") => [ 'Europe/Brussels', 'Europe/Paris', 'Europe/Berlin' ],
- N_("Brazil") => [ 'America/Sao_Paulo' ],
- N_("Canada") => [ 'Canada/Atlantic', 'Canada/Eastern' ],
- N_("Costa Rica") => [ 'America/Costa_Rica' ],
- N_("Czech Republic") => [ 'Europe/Prague', 'Europe/Berlin' ],
- N_("Denmark") => [ 'Europe/Copenhagen', 'Europe/Berlin' ],
- N_("Estonia") => [ 'Europe/Tallinn', 'Europe/Helsinki' ],
- N_("Finland") => [ 'Europe/Helsinki', 'Europe/Tallinn' ],
- N_("France") => [ 'Europe/Paris', 'Europe/Brussels', 'Europe/Berlin' ],
- N_("Germany") => [ 'Europe/Berlin', 'Europe/Prague' ],
- N_("Greece") => [ 'Europe/Athens', 'Europe/Prague' ],
- N_("Hungary") => [ 'Europe/Budapest' ],
- N_("Ireland") => [ 'Europe/Dublin', 'Europe/London' ],
- N_("Israel") => [ 'Asia/Tel_Aviv' ],
- N_("Italy") => [ 'Europe/Rome', 'Europe/Brussels', 'Europe/Paris' ],
- N_("Japan") => [ 'Asia/Tokyo', 'Asia/Seoul' ],
- N_("Netherlands") => [ 'Europe/Amsterdam', 'Europe/Brussels', 'Europe/Berlin' ],
- N_("New Zealand") => [ 'Pacific/Auckland' ],
- N_("Norway") => [ 'Europe/Oslo', 'Europe/Stockholm' ],
- N_("Poland") => [ 'Europe/Warsaw' ],
- N_("Portugal") => [ 'Europe/Lisbon', 'Europe/Madrid' ],
- N_("Russia") => [ 'Europe/Moscow', ],
- N_("Slovakia") => [ 'Europe/Bratislava' ],
- N_("South Africa") => [ 'Africa/Johannesburg' ],
- N_("Spain") => [ 'Europe/Madrid', 'Europe/Lisbon' ],
- N_("Sweden") => [ 'Europe/Stockholm', 'Europe/Oslo' ],
- N_("Switzerland") => [ 'Europe/Zurich', 'Europe/Berlin', 'Europe/Brussels' ],
- N_("Taiwan") => [ 'Asia/Taipei', 'Asia/Seoul' ],
- N_("Thailand") => [ 'Asia/Bangkok', 'Asia/Seoul' ],
- N_("United States") => [ 'America/New_York', 'Canada/Atlantic', 'Asia/Tokyo', 'Australia/Sydney', 'Europe/Paris' ],
- );
+=head1 SYNOPSYS
+
+B<mirror> enables to manage Mageia distribution mirrors
+
+=head1 Functions
+
+=over
+
+=cut
+
+=item mirror2text($mirror)
+
+Returns a displayable string from a mirror struct
+
+=cut
sub mirror2text {
my ($mirror) = @_;
translate($mirror->{country}) . '|' . $mirror->{host} . ($mirror->{method} ? " ($mirror->{method})" : '');
}
+=item register_downloader($func)
+
+Sets a downloader program
+
+=cut
+
my $downloader;
sub register_downloader {
my ($func) = @_;
@@ -78,19 +65,36 @@ sub _mirrors_raw_standalone {
@lines;
}
+=item mirrors_raw($product_id)
+
+Returns a list of mirrors hash refs from http://mirrors.mageia.org
+
+Note that in standalone mode, one has to actually use register_downloader()
+first in order to provide a downloader callback.
+
+=cut
+
sub mirrors_raw {
my ($product_id) = @_;
#- contact the following URL to retrieve the list of mirrors.
#- http://wiki.mageia.org/en/Product_id
my $type = lc($product_id->{type}); $type =~ s/\s//g;
- #- FIXME! (blino) we use use https here
- my $list = "http://mirrors.mageia.org/api/$type.$product_id->{version}.$product_id->{arch}.list?product=$product_id->{product}";
+ my $list = "https://mirrors.mageia.org/api/$type.$product_id->{version}.$product_id->{arch}.list?product=$product_id->{product}";
log::explanations("trying mirror list from $list");
my @lines = $::isInstall ? _mirrors_raw_install($list) : _mirrors_raw_standalone($list);
map { common::parse_LDAP_namespace_structure(chomp_($_)) } @lines;
}
+=item list($product_id, $type)
+
+
+Returns a list of mirrors hash refs as returned by mirrors_raw() but filters it.
+
+One can select the type of mirrors ('distrib', 'updates', ...) or 'all'
+
+=cut
+
sub list {
my ($product_id, $type) = @_;
@@ -105,27 +109,84 @@ sub list {
}
my @mirrors = grep {
- ($_->{method}, $_->{host}, $_->{dir}) = $_->{url} =~ m!^(ftp|http)://(.*?)(/.*)!;
- $_->{method} && ($type eq 'all' || $_->{type} eq $type);
+ ($_->{method}, $_->{host}, $_->{dir}) = $_->{url} =~ m!^(ftp|https?)://(.*?)(/.*)!;
+ $_->{method} && (member($type, 'all', $_->{type}));
} @mirrors_raw or log::explanations("no mirrors of type $type"), return;
@mirrors && \@mirrors;
}
+=item nearest($timezone, $mirrors)
+
+Randomly returns one of the nearest mirror
+
+=cut
+
+#- TODO: The following code was forked from urpm::mirrors. Consider refactoring.
+
sub nearest {
my ($timezone, $mirrors) = @_;
- my (@country, @zone);
- foreach my $mirror (@$mirrors) {
- my @tzs = @{$land2tzs{$mirror->{country}} || []};
- eval { push @{$country[find_index { $_ eq $timezone } @tzs]}, $mirror };
- eval { push @{$zone[find_index { ((split '/')[0] eq (split '/', $timezone)[0]) } @tzs]}, $mirror };
+ my ($latitude, $longitude, $country_code);
+
+ require Time::ZoneInfo;
+ if (my $zones = Time::ZoneInfo->new) {
+ if (($latitude, $longitude) = $zones->latitude_longitude_decimal($timezone)) {
+ $country_code = $zones->country($timezone);
+ }
+ }
+ defined $latitude && defined $longitude or return;
+
+ foreach (@$mirrors) {
+ $_->{latitude} || $_->{longitude} or next;
+ my $PI = 3.14159265358979;
+ my $x = $latitude - $_->{latitude};
+ my $y = ($longitude - $_->{longitude}) * cos($_->{latitude} / 180 * $PI);
+ $_->{proximity} = sqrt($x * $x + $y * $y);
}
- my @l = @country ? @country : @zone;
- shift @l while !$l[0] && @l;
-
- my @possible = @l ? ((@{$l[0]}) x 2, @{$l[1] || []}) : @$mirrors;
- $possible[rand @possible];
+ my ($best) = sort { $a->{proximity} <=> $b->{proximity} } @$mirrors;
+
+ foreach (@$mirrors) {
+ $_->{proximity_corrected} = $_->{proximity} * _random_correction();
+ $_->{proximity_corrected} *= _between_country_correction($country_code, $_->{country}) if $best;
+ $_->{proximity_corrected} *= _between_continent_correction($best->{continent}, $_->{continent}) if $best;
+ $_->{proximity_corrected} *= _protocol_correction($_->{url});
+ }
+ ($best) = sort { $a->{proximity_corrected} <=> $b->{proximity_corrected} } @$mirrors;
+ $best;
}
+# add +/- 5% random
+sub _random_correction() {
+ my $correction = 0.05;
+ 1 + (rand() - 0.5) * $correction * 2;
+}
+
+sub _between_country_correction {
+ my ($here, $mirror) = @_;
+ $here && $mirror or return 1;
+ $here eq $mirror ? 0.5 : 1;
+}
+
+sub _between_continent_correction {
+ my ($here, $mirror) = @_;
+ $here && $mirror or return 1;
+ $here eq $mirror ? 0.5 : # favor same continent
+ $here eq 'SA' && $mirror eq 'NA' ? 0.9 : # favor going "South America" -> "North America"
+ 1;
+}
+
+sub _protocol_correction {
+ my ($url) = @_;
+ # favor encrypted protocols, then http
+ ( $url =~ m!https://! ) and return 0.7;
+ ( $url =~ m!ftps://! ) and return 0.8;
+ ( $url =~ m!http://! ) and return 0.9;
+ 1;
+}
+
+=back
+
+=cut
+
1;