From 030b6b447881e215d7fcc1b4e2c3911986d549cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 22 Jun 2015 13:05:03 +0200 Subject: [PATCH] Software Update: version cache will be written to disk Reduces number of requests done against (rate limited) github API, especially after consecutive server restarts. Forcing the update check still will query the API. --- .../plugins/softwareupdate/__init__.py | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/octoprint/plugins/softwareupdate/__init__.py b/src/octoprint/plugins/softwareupdate/__init__.py index fd3bd0d1..779c6af0 100644 --- a/src/octoprint/plugins/softwareupdate/__init__.py +++ b/src/octoprint/plugins/softwareupdate/__init__.py @@ -37,9 +37,13 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, self._version_cache = dict() self._version_cache_ttl = 0 + self._version_cache_path = None + self._version_cache_dirty = False def initialize(self): self._version_cache_ttl = self._settings.get_int(["cache_ttl"]) * 60 + self._version_cache_path = os.path.join(self._settings.get_plugin_data_folder(), "versioncache.yaml") + self._load_version_cache() def refresh_checks(name, plugin): self._refresh_configured_checks = True @@ -67,6 +71,41 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, return self._configured_checks + def _load_version_cache(self): + if not os.path.isfile(self._version_cache_path): + return + + import yaml + try: + with open(self._version_cache_path) as f: + data = yaml.safe_load(f) + except: + self._logger.exception("Error while loading version cache from disk") + else: + self._version_cache = data + self._version_cache_dirty = False + self._logger.info("Loaded version cache from disk") + + def _save_version_cache(self): + import tempfile + import yaml + import shutil + + file_obj = tempfile.NamedTemporaryFile(delete=False) + try: + yaml.safe_dump(self._version_cache, stream=file_obj, default_flow_style=False, indent=" ", allow_unicode=True) + file_obj.close() + shutil.move(file_obj.name, self._version_cache_path) + + self._version_cache_dirty = False + self._logger.info("Saved version cache to disk") + finally: + try: + if os.path.exists(file_obj.name): + os.remove(file_obj.name) + except Exception as e: + self._logger.warn("Could not delete file {}: {}".format(file_obj.name, str(e))) + #~~ SettingsPlugin API def get_settings_defaults(self): @@ -84,7 +123,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, "octoprint_restart_command": None, "environment_restart_command": None, - "cache_ttl": 60, + "cache_ttl": 24 * 60, } def on_settings_save(self, data): @@ -280,6 +319,8 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, local_value = target_information["local"]["value"] information[target]["displayVersion"] = check["displayVersion"].format(octoprint_version=octoprint_version, local_name=local_name, local_value=local_value) + if self._version_cache_dirty: + self._save_version_cache() return information, update_available, update_possible def _get_current_version(self, target, check, force=False): @@ -289,7 +330,8 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, if target in self._version_cache and not force: timestamp, information, update_available, update_possible = self._version_cache[target] - if timestamp + self._version_cache_ttl >= time.time(): + if timestamp + self._version_cache_ttl >= time.time() > timestamp: + # we also check that timestamp < now to not get confused too much by clock changes return information, update_available, update_possible information = dict() @@ -314,6 +356,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, update_possible = False self._version_cache[target] = (time.time(), information, update_available, update_possible) + self._version_cache_dirty = True return information, update_available, update_possible def _send_client_message(self, message_type, data=None): @@ -390,6 +433,8 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, self._send_client_message("error", dict(results=target_results)) else: + self._save_version_cache() + # otherwise the update process was a success, but we might still have to restart if restart_type is not None and restart_type in ("octoprint", "environment"): # one of our updates requires a restart of either type "octoprint" or "environment". Let's see if @@ -468,6 +513,9 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, # load will overwrite our changes we just made self._settings.save() + del self._version_cache[target] + self._version_cache_dirty = True + return target_error, target_result def _perform_restart(self, restart_command):