geo.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. from __future__ import annotations
  2. from dataclasses import dataclass
  3. from typing import Optional
  4. from app.config import settings
  5. @dataclass
  6. class GeoInfo:
  7. country: str
  8. city: str
  9. latitude: Optional[float]
  10. longitude: Optional[float]
  11. org: Optional[str] = None
  12. _UNKNOWN = GeoInfo("Unknown", "Unknown", None, None, None)
  13. class GeoResolver:
  14. def __init__(self, db_path: str, asn_db_path: str) -> None:
  15. self._db_path = db_path
  16. self._asn_db_path = asn_db_path
  17. self._reader = None
  18. self._asn_reader = None
  19. def _get_reader(self):
  20. if self._reader is None:
  21. import geoip2.database
  22. self._reader = geoip2.database.Reader(self._db_path)
  23. return self._reader
  24. def _get_asn_reader(self):
  25. if self._asn_reader is None:
  26. import geoip2.database
  27. self._asn_reader = geoip2.database.Reader(self._asn_db_path)
  28. return self._asn_reader
  29. def resolve(self, ip: str) -> GeoInfo:
  30. # Private / loopback addresses have no GeoIP entry
  31. if ip in ("127.0.0.1", "::1", "localhost") or ip.startswith("192.168.") or ip.startswith("10.") or ip.startswith("172."):
  32. return GeoInfo("Local", "Loopback", None, None, None)
  33. try:
  34. reader = self._get_reader()
  35. response = reader.city(ip)
  36. country = response.country.name or "Unknown"
  37. city = response.city.name or "Unknown"
  38. lat = response.location.latitude
  39. lon = response.location.longitude
  40. except Exception:
  41. country, city, lat, lon = "Unknown", "Unknown", None, None
  42. org = None
  43. try:
  44. asn_reader = self._get_asn_reader()
  45. asn_response = asn_reader.asn(ip)
  46. org = asn_response.autonomous_system_organization or None
  47. except Exception:
  48. pass
  49. return GeoInfo(country, city, lat, lon, org)
  50. geo_resolver = GeoResolver(settings.geoip_db_path, settings.geoip_asn_db_path)