7 use Math::Trig qw(deg2rad pip2 great_circle_distance);
14 my $source = shift @ARGV;
15 my $zone = shift @ARGV;
16 my $servers = YAML::LoadFile("src/${source}");
18 foreach my $server (values %$servers)
20 $server->{status} = "down";
23 if ($ENV{PINGDOM_USERNAME} && $ENV{PINGDOM_PASSWORD})
25 my $ua = LWP::UserAgent->new;
27 $ua->default_header("App-Key", "2cohi62u5haxvqmypk3ljqqrze1jufrh");
28 $ua->credentials("api.pingdom.com:443", "Pingdom API", $ENV{PINGDOM_USERNAME}, $ENV{PINGDOM_PASSWORD});
30 foreach my $server (values %$servers)
32 if (my $checkid = $server->{pingdom})
34 my $response = $ua->get("https://api.pingdom.com/api/2.0/checks/${checkid}");
36 if ($response->is_success)
38 my $check = decode_json($response->content);
40 $server->{status} = $check->{check}->{status};
48 my $countries = XML::TreeBuilder->new;
50 $countries->parsefile("lib/countries.xml");
52 foreach my $country ($countries->look_down("_tag" => "country"))
54 my $code = $country->look_down("_tag" => "countryCode")->as_text;
55 my $name = $country->look_down("_tag" => "countryName")->as_text;
56 my $continent = $country->look_down("_tag" => "continent")->as_text;
57 my $west = $country->look_down("_tag" => "bBoxWest")->as_text;
58 my $north = $country->look_down("_tag" => "bBoxNorth")->as_text;
59 my $east = $country->look_down("_tag" => "bBoxEast")->as_text;
60 my $south = $country->look_down("_tag" => "bBoxSouth")->as_text;
61 my $lat = centre_lat( $south, $north );
62 my $lon = centre_lon( $west, $east );
65 foreach my $servername (keys %$servers)
67 my $server = $servers->{$servername};
68 my $match = match_country($server, $code, $continent);
70 if ($match eq "preferred" || $match eq "allowed")
72 my $priority = $match eq "preferred" ? 20 : 10;
73 my $distance = distance($lat, $lon, $server->{lat}, $server->{lon});
75 $priority = $priority * 10 if $server->{status} eq "up";
77 # print STDERR "$servername is $match for $name with distance $distance\n";
79 push @servers, { name => $servername, priority => $priority, distance => $distance };
84 code => $code, name => $name, continent => $continent,
85 lat => $lat, lon => $lon, servers => \@servers
91 my $zonefile = IO::File->new("> data/${zone}") || die "$!";
92 my $kmlfile = IO::File->new("> kml/${zone}.kml") || die "$!";
93 my $kmlwriter = XML::Writer->new(OUTPUT => $kmlfile, ENCODING => 'utf-8');
95 $kmlwriter->xmlDecl();
96 $kmlwriter->startTag("kml", "xmlns" => "http://www.opengis.net/kml/2.2");
97 $kmlwriter->startTag("Document");
99 foreach my $country (values %countries)
101 my @servers = sort { $b->{priority} <=> $a->{priority} || $a->{distance} <=> $b->{distance} } @{$country->{servers}};
102 my $server = $servers->{$servers[0]->{name}};
103 my $clon = $country->{lon};
104 my $clat = $country->{lat};
105 my $slon = $server->{lon};
106 my $slat = $server->{lat};
108 if ($clon > 0 && $slon < 0 && 360 + $slon - $clon < $clon - $slon)
113 $zonefile->print("C\L$country->{code}\E.${zone}:$servers[0]->{name}.${zone}:600\n");
115 $kmlwriter->startTag("Placemark");
116 $kmlwriter->dataElement("name", $country->{name});
117 $kmlwriter->startTag("LineString");
118 $kmlwriter->dataElement("coordinates", "$clon,$clat $slon,$slat");
119 $kmlwriter->endTag("LineString");
120 $kmlwriter->endTag("Placemark");
123 foreach my $server (grep { $servers->{$_}->{default} } keys %$servers)
125 $zonefile->print("Cxx.${zone}:${server}.${zone}:600\n");
128 $kmlwriter->endTag("Document");
129 $kmlwriter->endTag("kml");
142 return ( $south + $north ) / 2;
153 $lon = ( $west + $east ) / 2;
157 $lon = ( $west + $east + 360 ) / 2;
160 $lon = $lon - 360 if $lon > 180;
169 my $continent = shift;
172 if ($server->{preferred} &&
173 $server->{preferred}->{countries} &&
174 grep { $_ eq $country } @{$server->{preferred}->{countries}})
176 $match = "preferred";
178 elsif ($server->{preferred} &&
179 $server->{preferred}->{continents} &&
180 grep { $_ eq $continent } @{$server->{preferred}->{continents}})
182 $match = "preferred";
184 elsif ($server->{allowed} &&
185 $server->{allowed}->{countries} &&
186 grep { $_ eq $country } @{$server->{allowed}->{countries}})
190 elsif ($server->{allowed} &&
191 $server->{allowed}->{continents} &&
192 grep { $_ eq $continent } @{$server->{allowed}->{continents}})
196 elsif ($server->{allowed})
210 my $lat1 = deg2rad(shift);
211 my $lon1 = deg2rad(shift);
212 my $lat2 = deg2rad(shift);
213 my $lon2 = deg2rad(shift);
215 return great_circle_distance($lon1, pip2 - $lat1, $lon2, pip2 - $lat2);