[PATCH] Make the Welcome spoke wait for Geolocation lookup to finish (#975193)
Martin Kolman
mkolman at redhat.com
Mon Jul 8 17:33:22 UTC 2013
The GeoIP lookup usually takes between 1 to 2 seconds to finish.
In some cases, such as when running on a live system, the welcome spoke
might show up before the lookup can finish, so the result of the lookup
can not be used to pre-set the language.
To improve this, the geoloc module top level functions now have an
optional wait parameter, that makes the function block until the
lookup is is done or a timeout is reached.
The end result is, that the Welcome spoke will wait up to 3 seconds
for the lookup to finish. Usually it would wait less than 2 seconds or
not at all (if the lookup finishes before the welcome spoke is even
initialized).
Signed-off-by: Martin Kolman <mkolman at gmail.com>
---
pyanaconda/constants.py | 3 ++
pyanaconda/geoloc.py | 69 +++++++++++++++++++++++++++++++++----
pyanaconda/ui/gui/spokes/welcome.py | 2 +-
3 files changed, 66 insertions(+), 8 deletions(-)
diff --git a/pyanaconda/constants.py b/pyanaconda/constants.py
index ee9ffdb..175dc36 100644
--- a/pyanaconda/constants.py
+++ b/pyanaconda/constants.py
@@ -141,6 +141,9 @@ GEOLOC_GEOCODER_NOMINATIM = "geocoder_nominatim"
# default providers
GEOLOC_DEFAULT_PROVIDER = GEOLOC_PROVIDER_FEDORA_GEOIP
GEOLOC_DEFAULT_GEOCODER = GEOLOC_GEOCODER_NOMINATIM
+# timeout (in seconds)
+GEOLOC_TIMEOUT = 3
+
ANACONDA_ENVIRON = "anaconda"
FIRSTBOOT_ENVIRON = "firstboot"
diff --git a/pyanaconda/geoloc.py b/pyanaconda/geoloc.py
index 5a6da14..d859621 100644
--- a/pyanaconda/geoloc.py
+++ b/pyanaconda/geoloc.py
@@ -116,6 +116,8 @@ from pyanaconda.threads import AnacondaThread, threadMgr
from pyanaconda import nm
location_info_instance = None
+refresh_condition = threading.Condition()
+refresh_in_progress = False
def init_geolocation(provider_id=constants.GEOLOC_DEFAULT_PROVIDER):
@@ -143,7 +145,7 @@ def refresh():
log.debug("Geoloc: refresh() called before init_geolocation()")
-def get_territory_code():
+def get_territory_code(wait=False):
"""This function returns the current country code
or None, if:
- no results were found
@@ -151,16 +153,17 @@ def get_territory_code():
- the geolocation module was not activated (init & refresh were not called)
- this is for example the case during image and directory installs
+ :param wait: wait for wait seconds for lookup in progress to finish
:return: current country code or None if not known
:rtype: string or None
"""
- if location_info_instance:
+ if _get_location_info_instance(wait):
return location_info_instance.get_territory_code()
else:
return None
-def get_timezone():
+def get_timezone(wait=False):
"""This function returns the current time zone
or None, if:
- no timezone was found
@@ -168,28 +171,29 @@ def get_timezone():
- the geolocation module was not activated (init & refresh were not called)
- this is for example the case during image and directory installs
+ :param wait: wait for wait seconds for lookup in progress to finish
:return: current timezone or None if not known
:rtype: string or None
"""
- if location_info_instance:
+ if _get_location_info_instance(wait):
return location_info_instance.get_timezone()
else:
return None
-def get_result():
+def get_result(wait=False):
"""Returns the current geolocation result wrapper
or None, if:
- no results were found
- the refresh is still in progress
- the geolocation module was not activated (init & refresh were not called)
-
- this is for example the case during image and directory installs
+ :param wait: wait for wait seconds for lookup in progress to finish
:return: LocationResult instance or None if location is unknown
:rtype: LocationResult or None
"""
- if location_info_instance:
+ if _get_location_info_instance(wait):
return location_info_instance.get_result()
else:
return None
@@ -236,6 +240,50 @@ def _get_provider(provider_id):
return provider()
+def _get_location_info_instance(wait=False):
+ """Return instance of the location info object
+ and optionally wait for the Geolocation thread to finish
+
+ If there is no lookup in progress (no Geolocation refresh thread
+ is running), this function returns at once).
+
+ Meaning of the wait parameter:
+ - False or <=0: don't wait
+ - True : wait for default number of seconds specified by
+ the GEOLOC_TIMEOUT constant
+ - >0 : wait for a given number of seconds
+
+ :param wait: specifies if this function should wait
+ for the lookup to finish before returning the instance
+ :type wait: bool or integer or float
+ """
+ if not wait:
+ # just returns the instance
+ return location_info_instance
+
+ # check if wait is a boolean or a number
+ if wait is True:
+ # use the default waiting period
+ wait = constants.GEOLOC_TIMEOUT
+ # check if there is a refresh in progress
+ start_time = time.time()
+ refresh_condition.acquire()
+ if refresh_in_progress:
+ refresh_condition.wait(timeout=wait)
+ if refresh_in_progress:
+ log.info("Waiting for Geolocation timed out after %d seconds."
+ % wait)
+ # please note that this does not mean that the actual
+ # geolocation lookup was stopped in any way, it just
+ # means the caller was unblocked after the waiting period
+ # ended while the lookup thread is still running
+ else:
+ elapsed_time = time.time() - start_time
+ log.info("Waited %1.2f seconds for Geolocation" % elapsed_time)
+ refresh_condition.release()
+ return location_info_instance
+
+
class GeolocationError(Exception):
"""Exception class for geolocation related errors"""
pass
@@ -413,6 +461,9 @@ class GeolocationBackend(object):
if force is True or self._result is None:
log.info("Starting geolocation lookup")
log.info("Geolocation provider: %s" % self.get_name())
+ global refresh_in_progress
+ with refresh_condition:
+ refresh_in_progress = True
try:
start_time = time.time()
self._refresh()
@@ -422,6 +473,10 @@ class GeolocationBackend(object):
message = "GeoIP lookup ended with exception"
message += "\n%s" % e
log.debug(message)
+ with refresh_condition:
+ refresh_in_progress = False
+ refresh_condition.notify_all()
+ # check if there were any results
result = self.get_result()
if result:
log.info("%s" % result)
diff --git a/pyanaconda/ui/gui/spokes/welcome.py b/pyanaconda/ui/gui/spokes/welcome.py
index 5c3a47f..fec9b68 100644
--- a/pyanaconda/ui/gui/spokes/welcome.py
+++ b/pyanaconda/ui/gui/spokes/welcome.py
@@ -156,7 +156,7 @@ class WelcomeLanguageSpoke(StandaloneSpoke):
# We can use the territory from geolocation here
# to preselect the translation, when it's available.
- territory = geoloc.get_territory_code()
+ territory = geoloc.get_territory_code(wait=True)
self.language = Language(LOCALE_PREFERENCES, territory=territory)
# check if there is one and only one locale for the territory
--
1.8.3.1
More information about the anaconda-patches
mailing list