</tr>
{% if item.prefer_for_countries %}
<tr>
- <td>{{ _("Preferred for") }}:</td>
+ <td>{{ _("Preferred for") }}</td>
<td>{{ locale.list(item.prefer_for_countries_names) }}</td>
</tr>
{% end %}
+ {% if client_distance %}
+ <tr>
+ <td>{{ _("Your distance to this mirror") }}</td>
+ <td>{{ "%.1f km" % client_distance }}</td>
+ </tr>
+ {% end %}
</table>
<a class="btn pull-right" href="{{ item.url }}">{{ _("Go to mirror") }}</a>
<p>
{{ _("The mirror <em>%s</em> is located in %s.") % (item.hostname, item.location_str) }}
</p>
- <p>
- <img class="map"
- src="http://maps.google.com/maps/api/staticmap?center={{ item.coordiante_str }}&size=640x280&zoom=6&markers=color:blue|label:.|{{ item.coordiante_str }}&sensor=false"
- alt="{{ _("Location of the server") }}" />
- </p>
+
+ {% if item.longitude and item.latitude %}
+ <iframe width="100%" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"
+ src="http://www.openstreetmap.org/export/embed.html?bbox={{ item.longitude - 4 }},{{ item.latitude - 4 }},{{ item.longitude + 4 }},{{ item.latitude + 4 }}&layer=mapquest&marker={{ item.latitude }},{{ item.longitude }}" style="border: 1px solid black">
+ </iframe>
+ <p>
+ <a href="http://www.openstreetmap.org/?lat={{ item.latitude }}&lon={{ item.longitude }}&zoom=8&layers=M&mlat={{ item.latitude }}&mlon={{ item.longitude }}" target="_blank">{{ _("View larger map") }}</a>
+ -
+ © <a href="http://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> contributors, CC-BY-SA
+ </p>
+ <p class="muted ac">
+ {{ _("The location of the mirror server is estimated by the IP address.") }}
+ </p>
+ {% else %}
+ {{ _("The location of the mirror server could not be estimated.") }}
+ {% end %}
{% end block %}
</p>
{% end %}
- {% if other_mirrors %}
+ {% if preferred_mirrors %}
<h2>{{ _("Mirror servers nearby") }}</h2>
{{ modules.MirrorsTable(preferred_mirrors) }}
{{ modules.MirrorsTable(other_mirrors) }}
{% else %}
<h2>{{ _("Worldwide mirror servers") }}</h2>
- {{ modules.MirrorsTable(preferred_mirrors) }}
+ {{ modules.MirrorsTable(other_mirrors) }}
{% end %}
{% end block %}
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-11-08 21:41+0100\n"
+"POT-Creation-Date: 2012-11-29 18:31+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
msgid "Wish"
msgstr ""
-#: templates/wishlist/wish.html:16
+#: templates/wishlist/wish.html:18
#, python-format
msgid "Launched: %s"
msgstr ""
-#: templates/wishlist/wish.html:20
+#: templates/wishlist/wish.html:23
#, python-format
msgid "Funding ends: %s"
msgstr ""
msgstr ""
#: templates/mirrors-item.html:37
+msgid "Your distance to this mirror"
+msgstr ""
+
+#: templates/mirrors-item.html:43
msgid "Go to mirror"
msgstr ""
-#: templates/mirrors-item.html:42
+#: templates/mirrors-item.html:48
msgid "Mirror location"
msgstr ""
-#: templates/mirrors-item.html:44
+#: templates/mirrors-item.html:50
#, python-format
msgid "The mirror <em>%s</em> is located in %s."
msgstr ""
+#: templates/mirrors-item.html:58
+msgid "View larger map"
+msgstr ""
+
+#: templates/mirrors-item.html:63
+msgid "The location of the mirror server is estimated by the IP address."
+msgstr ""
+
+#: templates/mirrors-item.html:66
+msgid "The location of the mirror server could not be estimated."
+msgstr ""
+
#: templates/admin-downloads-mirrors.html:5 templates/admin-downloads.html:5
msgid "Download statistics"
msgstr ""
msgid "%s to %s"
msgstr ""
-#: webapp/backend/wishlist.py:128
+#: webapp/backend/wishlist.py:135
msgid "Checkout this crowdfunding wish from #ipfire:"
msgstr ""
class GeoIP(object):
__metaclass__ = Singleton
- def __init__(self):
- self.__country_codes = self.db.query("SELECT code, name FROM iso3166_countries")
-
@property
def db(self):
return Databases().geoip
- @property
- def memcached(self):
- return Memcached()
-
- def __encode_ip(self, addr):
+ def _encode_ip(self, addr):
# We get a tuple if there were proxy headers.
addr = addr.split(", ")
if addr:
addr = addr[-1]
- # ip is calculated as described in http://ipinfodb.com/ip_database.php
+ # ip is calculated as described in http://dev.maxmind.com/geoip/csv
a1, a2, a3, a4 = addr.split(".")
- return int(((int(a1) * 256 + int(a2)) * 256 + int(a3)) * 256 + int(a4) + 100)
+ try:
+ a1 = int(a1)
+ a2 = int(a2)
+ a3 = int(a3)
+ a4 = int(a4)
+ except ValueError:
+ return 0
+
+ return (16777216 * a1) + (65536 * a2) + (256 * a3) + a4
def get_country(self, addr):
- addr = self.__encode_ip(addr)
+ addr = self._encode_ip(addr)
- mem_id = "geoip-country-%s" % addr
- ret = self.memcached.get(mem_id)
+ ret = self.db.get("SELECT locations.country_code AS country_code FROM addresses \
+ JOIN locations ON locations.id = addresses.location \
+ WHERE %s BETWEEN start_ip_num AND end_ip_num LIMIT 1", addr)
- if not ret:
- ret = self.db.get("SELECT * FROM ip_group_country WHERE ip_start <= %s \
- ORDER BY ip_start DESC LIMIT 1;", addr).country_code.lower()
- self.memcached.set(mem_id, ret, 3600)
-
- return ret
+ if ret:
+ return ret.country_code
def get_all(self, addr):
- addr = self.__encode_ip(addr)
+ addr = self._encode_ip(addr)
- mem_id = "geoip-all-%s" % addr
- ret = self.memcached.get(mem_id)
+ ret = self.db.get("SELECT locations.* FROM addresses \
+ JOIN locations ON locations.id = addresses.location \
+ WHERE %s BETWEEN start_ip_num AND end_ip_num LIMIT 1", addr)
if not ret:
- # XXX should be done with a join
- location = self.db.get("SELECT location FROM ip_group_city WHERE ip_start <= %s \
- ORDER BY ip_start DESC LIMIT 1;", addr).location
-
- ret = self.db.get("SELECT * FROM locations WHERE id = %s", int(location))
- self.memcached.set(mem_id, ret, 3600)
+ return
# If location was not determinable
if ret.latitude == 0 and ret.longitude == 0:
return ret
def get_country_name(self, code):
- name = "Unknown"
-
- code = code.upper()
- for country in self.__country_codes:
- if country.code == code:
- name = country.name
- break
+ name = "Unkown"
+
+ codes = {
+ "A1" : "Anonymous Proxy",
+ "A2" : "Satellite Provider",
+ "EU" : "Europe",
+ "AP" : "Asia/Pacific Region",
+ }
+
+ # Return description of some exceptional codes.
+ try:
+ return codes[code]
+ except KeyError:
+ pass
+
+ ret = self.db.get("SELECT name FROM iso3166_countries WHERE code = %s LIMIT 1", code)
+ if ret:
+ name = ret.name
# Fix some weird strings
name = re.sub(r"(.*) (.* Republic of)", r"\2 \1", name)
mirrors = []
all_mirrors = self.list()
+ location = GeoIP().get_all(addr)
+ if not location:
+ return None
+
while all_mirrors and len(mirrors) <= 2 and distance <= 270:
for mirror in all_mirrors:
- if mirror.distance_to(addr) <= distance:
+ if mirror.distance_to(location) <= distance:
mirrors.append(mirror)
all_mirrors.remove(mirror)
mirrors = []
- while len(mirrors) <= 2 and distance <= 270:
- for mirror in self._mirrors:
- if mirror in mirrors:
- continue
+ location = GeoIP().get_all(addr)
+ if location:
+ while len(mirrors) <= 2 and distance <= 270:
+ for mirror in self._mirrors:
+ if mirror in mirrors:
+ continue
- if mirror.distance_to(addr) <= distance:
- mirrors.append(mirror)
+ if mirror.distance_to(location) <= distance:
+ mirrors.append(mirror)
- distance *= 1.2
+ distance *= 1.2
return MirrorSet(mirrors)
self.reload()
+ self.__location = None
+ self.__country_name = None
+
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, self.url)
@property
def location(self):
- if not hasattr(self, "__location"):
+ if self.__location is None:
self.__location = GeoIP().get_all(self.address)
return self.__location
@property
def country_code(self):
- return GeoIP().get_country(self.address).lower() or "unknown"
+ return self.location.country_code.lower() or "unknown"
@property
def country_name(self):
- return GeoIP().get_country_name(self.country_code)
+ if self.__country_name is None:
+ self.__country_name = GeoIP().get_country_name(self.country_code)
+
+ return self.__country_name
@property
def city(self):
def prefer_for_countries_names(self):
return sorted([GeoIP().get_country_name(c) for c in self.prefer_for_countries])
- def distance_to(self, addr):
- location = GeoIP().get_all(addr)
+ def distance_to(self, location, ignore_preference=False):
if not location:
return 0
- if location.country_code.lower() in self.prefer_for_countries:
+ if not ignore_preference and location.country_code.lower() in self.prefer_for_countries:
return 0
distance_vector = (
class MirrorItemHandler(BaseHandler):
def get(self, id):
- _ = self.locale.translate
-
mirror = self.mirrors.get(id)
if not mirror:
raise tornado.web.HTTPError(404)
- self.render("mirrors-item.html", item=mirror)
+ ip_addr = self.get_argument("addr", self.request.remote_ip)
+ client_location = self.geoip.get_all(ip_addr)
+
+ client_distance = mirror.distance_to(client_location, ignore_preference=True)
+ client_distance *= 111.32 # to km
+
+ self.render("mirrors-item.html", item=mirror,
+ client_distance=client_distance)
class MirrorHandler(BaseHandler):