2 # -*- coding: utf-8 -*-
6 # Copyright © 2013-2019 RebornOS
8 # This file is part of Cnchi.
10 # Cnchi is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 3 of the License, or
13 # (at your option) any later version.
15 # Cnchi is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # The following additional terms are in effect as per Section 7 of the license:
22 # The preservation of all legal notices and author attributions in
23 # the material or in the Appropriate Legal Notices displayed
24 # by works containing it is required.
26 # You should have received a copy of the GNU General Public License
27 # along with Cnchi; If not, see <http://www.gnu.org/licenses/>.
29 """ GeoIP Location module
30 Needs python-geoip2 python-maxminddb geoip2-database """
39 import geoip2.database
40 import misc.extra as misc
43 """ Store GeoIP information """
45 REPO_CITY_DATABASE = '/usr/share/GeoIP/GeoLite2-City.mmdb'
46 LOCAL_CITY_DATABASE = '/usr/share/cnchi/data/GeoLite2-City.mmdb'
48 SERVERS = ["ipapi.com", "ipgeolocation.io"]
52 self._maybe_wait_for_network()
53 self._load_data_and_ip()
56 def _maybe_wait_for_network():
57 # Wait until there is an Internet connection available
58 if not misc.has_connection():
60 "Can't get network status. Cnchi will try again in a moment")
61 while not misc.has_connection():
62 time.sleep(4) # Wait 4 seconds and try again
64 logging.debug("A working network connection has been detected.")
66 def _load_data_and_ip(self):
67 """ Gets public IP and loads GeoIP2 database """
68 db_path = GeoIP.REPO_CITY_DATABASE
69 if not os.path.exists(db_path):
70 db_path = GeoIP.LOCAL_CITY_DATABASE
72 if os.path.exists(db_path):
73 myip = self._get_external_ip()
74 logging.debug("Your external IP address is: %s", myip)
76 self._load_database(db_path, myip)
78 logging.debug("GeoIP database loaded (%s)", db_path)
80 logging.error("Cannot get your external IP address!")
82 logging.error("Cannot find Cities GeoIP database")
86 def _get_external_ip():
87 """ Get external IP """
88 for srv in GeoIP.SERVERS:
89 srv = "http://" + srv[::-1]
91 json_text = requests.get(srv).text
92 if not "503 Over Quota" in json_text:
93 data = json.loads(json_text)
95 except (requests.ConnectionError, json.decoder.JSONDecodeError) as err:
97 "Error getting external IP from %s: %s", srv, err)
100 def _load_database(self, db_path, myip):
101 """ Loads cities database """
103 reader = geoip2.database.Reader(db_path)
104 self.record = reader.city(myip)
105 except maxminddb.errors.InvalidDatabaseError as err:
109 """ Returns city information
110 'city': {'geoname_id', 'names'} """
112 return self.record.city
115 def get_country(self):
116 """ Returns country information
117 'country': {'geoname_id', 'is_in_european_union', 'iso_code', 'names'} """
119 return self.record.country
122 def get_continent(self):
123 """ Returns continent information
124 'continent': {'code', 'geoname_id', 'names'} """
126 return self.record.continent
129 def get_location(self):
130 """ Returns location information
131 'location': {'accuracy_radius', 'latitude', 'longitude', 'time_zone'} """
133 return self.record.location
141 print("City:", geo.get_city())
142 print("Country:", geo.get_country())
143 print("Continent:", geo.get_continent())
144 print("Location:", geo.get_location())
147 if __name__ == "__main__":