From 218bfa2235ddb2f3881ad93cc069f8eda40553f1 Mon Sep 17 00:00:00 2001 From: Tom Watson Date: Wed, 6 Jul 2022 01:05:25 +0700 Subject: [PATCH] Updated contrib/publicip module and util/location Added another API endpoint, Added options to display country name, country code, city name and lat/long coordinates, attempt to handle failure to fetch info from API endpoints cleanly --- bumblebee_status/modules/contrib/publicip.py | 127 ++++++++++++++++++- bumblebee_status/util/location.py | 49 ++++++- 2 files changed, 163 insertions(+), 13 deletions(-) diff --git a/bumblebee_status/modules/contrib/publicip.py b/bumblebee_status/modules/contrib/publicip.py index a74d708..5b061f4 100644 --- a/bumblebee_status/modules/contrib/publicip.py +++ b/bumblebee_status/modules/contrib/publicip.py @@ -1,22 +1,109 @@ -"""Displays public IP address +""" +Displays public IP address and, optionally, Country Name, Country Code & City Name +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 forces immediate update + +Parameters (Default in brackets)_ +ip (True) Public IP address +country_name (False) Display name of country associated with the IP +country_code (False) Display country code of country associated with the IP +city_name (False) Display name of city associated with the IP +coordinates (False) Display name of city associated with the IP +all (False) Display all information associate with the IP + +Examples +By default only the public IP is shown +bumblebee-status -m publicip + +To also include the country name... +bumblebee-status -m publicip -p publicip.country_name=True + +To include all ava + """ import core.module import core.widget import core.decorators - +import core.input +import util.format import util.location class Module(core.module.Module): - @core.decorators.every(minutes=60) + @core.decorators.every(minutes=5) def __init__(self, config, theme): super().__init__(config, theme, core.widget.Widget(self.public_ip)) - self.__ip = "" + 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 = "" # Coordinated assoicated with public IP address + + # Handle failure to get IP information + self.__ip_error = False + + # Process option paramaters + self.__show_ip = util.format.asbool( + self.parameter("ip", True) + ) + self.__show_country_name = util.format.asbool( + self.parameter("country_name", False) + ) + self.__show_country_code = util.format.asbool( + self.parameter("country_code", False) + ) + self.__show_city_name = util.format.asbool(self.parameter("city_name", False)) + self.__show_coordinates = util.format.asbool( + self.parameter("coordinates", False) + ) + self.__show_all = util.format.asbool(self.parameter("all", False)) + + def __click_update(self, event): + util.location.reset() def public_ip(self, widget): - return self.__ip or "n/a" + __output = "" + + if self.__ip: + if self.__show_ip or self.__show_all: + __output = self.__ip + self.__ip_error = False + else: + self.__ip_error = True + __output = "Error Getting IP" + + if not self.__ip_error: + if self.__show_country_name or self.__show_all: + if self.__country_name: + __output += " " + self.__country_name + else: + __output += " " + "?" + + if self.__show_country_code or self.__show_all: + if self.__country_code: + __output += " " + "(" + self.__country_code + ")" + else: + __output += " " + "(?)" + + if self.__show_city_name or self.__show_all: + if self.__city_name: + __output += " " + self.__city_name + else: + __output += " " + "?" + + if self.__show_coordinates or self.__show_all: + if self.__coordinates: + __output += " " + self.__coordinates + else: + __output += " " + "?" + + return __output def update(self): try: @@ -24,5 +111,33 @@ class Module(core.module.Module): except Exception: self.__ip = None + if self.__show_country_name or self.__show_all: + try: + self.__country_name = util.location.country_name() + except Exception: + self.__country_name = None -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 + if self.__show_country_code or self.__show_all: + try: + self.__country_code = util.location.country_code() + except Exception: + self.__country_code = None + + if self.__show_city_name or self.__show_all: + try: + self.__city_name = util.location.city_name() + except Exception: + self.__city_name = None + + if self.__show_coordinates or self.__show_all: + try: + __tmp = util.location.coordinates() + __lat = "{:.2f}".format(__tmp[0]) + __lon = "{:.2f}".format(__tmp[1]) + __output = __lat + "°N" + "," + " " + __lon + "°E" + self.__coordinates = __output + except Exception: + self.__city_name = None + + +# vim: tabstop=7 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee_status/util/location.py b/bumblebee_status/util/location.py index e48b71a..840baa0 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,9 +34,22 @@ __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,7 +80,10 @@ 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(): @@ -82,14 +102,29 @@ def coordinates(): return __get("latitude"), __get("longitude") -def country(): +def country_name(): """Returns the current country name :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(): """Returns the current public IP