summaryrefslogtreecommitdiff
path: root/addons/http_routing/geoipresolver.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/http_routing/geoipresolver.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/http_routing/geoipresolver.py')
-rw-r--r--addons/http_routing/geoipresolver.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/addons/http_routing/geoipresolver.py b/addons/http_routing/geoipresolver.py
new file mode 100644
index 00000000..2cd16952
--- /dev/null
+++ b/addons/http_routing/geoipresolver.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import os.path
+
+try:
+ import GeoIP # Legacy
+except ImportError:
+ GeoIP = None
+
+try:
+ import geoip2
+ import geoip2.database
+except ImportError:
+ geoip2 = None
+
+class GeoIPResolver(object):
+ def __init__(self, fname):
+ self.fname = fname
+ try:
+ self._db = geoip2.database.Reader(fname)
+ self.version = 2
+ except Exception:
+ try:
+ self._db = GeoIP.open(fname, GeoIP.GEOIP_STANDARD)
+ self.version = 1
+ assert self._db.database_info is not None
+ except Exception:
+ raise ValueError('Invalid GeoIP database: %r' % fname)
+
+ def __del__(self):
+ if self.version == 2:
+ self._db.close()
+
+ @classmethod
+ def open(cls, fname):
+ if not GeoIP and not geoip2:
+ return None
+ if not os.path.exists(fname):
+ return None
+ return GeoIPResolver(fname)
+
+ def resolve(self, ip):
+ if self.version == 1:
+ return self._db.record_by_addr(ip) or {}
+ elif self.version == 2:
+ try:
+ r = self._db.city(ip)
+ except (ValueError, geoip2.errors.AddressNotFoundError):
+ return {}
+ # Compatibility with Legacy database.
+ # Some ips cannot be located to a specific country. Legacy DB used to locate them in
+ # continent instead of country. Do the same to not change behavior of existing code.
+ country, attr = (r.country, 'iso_code') if r.country.geoname_id else (r.continent, 'code')
+ return {
+ 'city': r.city.name,
+ 'country_code': getattr(country, attr),
+ 'country_name': country.name,
+ 'latitude': r.location.latitude,
+ 'longitude': r.location.longitude,
+ 'region': r.subdivisions[0].iso_code if r.subdivisions else None,
+ 'time_zone': r.location.time_zone,
+ }
+
+ # compat
+ def record_by_addr(self, addr):
+ return self.resolve(addr)