diff --git a/bumblebee_status/modules/contrib/publicip.py b/bumblebee_status/modules/contrib/publicip.py index a74d708..d043fce 100644 --- a/bumblebee_status/modules/contrib/publicip.py +++ b/bumblebee_status/modules/contrib/publicip.py @@ -1,10 +1,38 @@ -"""Displays public IP address +""" +Displays zero or more of: + * Public IP address + * Country Name + * Country Code + * City Name + * Geographic Coordinates\ + +Maximum refresh interval should be 5 minutes to avoid free SLA breach from providers +Note: 1 request/5 minutes is 8640 requests/month +Provider information contained in core.location + +Left mouse click on the widget forces immediate update + +Parameters: +publicip.format: Format string (defaults to ‘{ip} ({country_code})’) + +Available format strings: +ip +country_name +country_code +city_name +coordinates + +Examples: +bumblebee-status -m publicip -p publicip.format="{ip} ({country_code})" +bumblebee-status -m publicip -p publicip.format="{ip} which is in {city_name}" +bumblebee-status -m publicip -p publicip.format="Your packets are right here: {coordinates}" """ import core.module import core.widget import core.decorators - +import core.input +import util.format import util.location @@ -13,16 +41,48 @@ class Module(core.module.Module): def __init__(self, config, theme): super().__init__(config, theme, core.widget.Widget(self.public_ip)) - self.__ip = "" + # Immediate update (override default) when left click on widget + core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__click_update) + + self.__ip = "" # Public IP address + self.__country_name = "" # Country name associated with public IP address + self.__country_code = "" # Country code associated with public IP address + self.__city_name = "" # City name associated with public IP address + self.__coordinates = "" # Coordinates assoicated with public IP address + + # By default show: (<2 letter country code>) + self._format = self.parameter("format", "{ip} ({country_code})") + + def __click_update(self, event): + util.location.reset() def public_ip(self, widget): - return self.__ip or "n/a" + if not self.__ip: + return "Error fetching IP" + else: + return self._format.format( + ip=self.__ip, + country_name=self.__country_name, + country_code=self.__country_code, + city_name=self.__city_name, + coordinates=self.__coordinates, + ) def update(self): try: - self.__ip = util.location.public_ip() + __info = util.location.location_info() + self.__ip = __info["public_ip"] + self.__country_name = __info["country"] + self.__country_code = __info["country_code"] + self.__city_name = __info["city_name"] + __lat = __info["latitude"] + __lon = __info["longitude"] + __lat = "{:.2f}".format(__lat) + __lon = "{:.2f}".format(__lon) + __output = __lat + "°N" + "," + " " + __lon + "°E" + self.__coordinates = __output except Exception: - self.__ip = None + pass -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +# vim: tabstop=7 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee_status/util/location.py b/bumblebee_status/util/location.py index e48b71a..1974773 100644 --- a/bumblebee_status/util/location.py +++ b/bumblebee_status/util/location.py @@ -3,8 +3,10 @@ service and caches it for 12h (retries are done every 30m in case of problems) Right now, it uses (in order of preference): - - http://free.ipwhois.io/ - - http://ipapi.co/ + - http://free.ipwhois.io/ - 10k free requests/month + - http://ipapi.co/ - 30k free requests/month + - http://ip-api.com/ - ~2m free requests/month + """ @@ -21,7 +23,9 @@ __sources = [ "mapping": { "latitude": "latitude", "longitude": "longitude", - "country_name": "country", + "country_name": "country_name", + "country_code": "country_code", + "city": "city_name", "ip": "public_ip", }, }, @@ -30,10 +34,23 @@ __sources = [ "mapping": { "latitude": "latitude", "longitude": "longitude", - "country": "country", + "country": "country_name", + "country_code": "country_code", + "city": "city_name", "ip": "public_ip", }, - } + }, + { + "url": "http://ip-api.com/json", + "mapping": { + "latitude": "lat", + "longitude": "lon", + "country": "country_name", + "countryCode": "country_code", + "city": "city_name", + "query": "public_ip", + }, + }, ] @@ -63,12 +80,14 @@ def __get(name): global __data if not __data or __expired(): __load() - return __data[name] + if name in __data: + return __data[name] + else: + return None def reset(): - """Resets the location library, ensuring that a new query will be started - """ + """Resets the location library, ensuring that a new query will be started""" global __next __next = 0 @@ -88,7 +107,25 @@ def country(): :return: country name :rtype: string """ - return __get("country") + return __get("country_name") + + +def country_code(): + """Returns the current country code + + :return: country code + :rtype: string + """ + return __get("country_code") + + +def city_name(): + """Returns the current city name + + :return: city name + :rtype: string + """ + return __get("city_name") def public_ip(): @@ -100,4 +137,20 @@ def public_ip(): return __get("public_ip") +def location_info(): + """Returns the current location information + + :return: public IP, country name, country code, city name & coordinates + :rtype: dictionary + """ + return { + "public_ip": __get("public_ip"), + "country": __get("country_name"), + "country_code": __get("country_code"), + "city_name": __get("city_name"), + "latitude": __get("latitude"), + "longitude": __get("longitude"), + } + + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4