parent
fb8c56be57
commit
0dcbffb9d2
7 changed files with 106 additions and 24 deletions
|
|
@ -28,7 +28,8 @@ class AnnouncementPlugin(octoprint.plugin.AssetPlugin,
|
|||
octoprint.plugin.SettingsPlugin,
|
||||
octoprint.plugin.BlueprintPlugin,
|
||||
octoprint.plugin.StartupPlugin,
|
||||
octoprint.plugin.TemplatePlugin):
|
||||
octoprint.plugin.TemplatePlugin,
|
||||
octoprint.plugin.EventHandlerPlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._cached_channel_configs = None
|
||||
|
|
@ -210,6 +211,14 @@ class AnnouncementPlugin(octoprint.plugin.AssetPlugin,
|
|||
|
||||
return NO_CONTENT
|
||||
|
||||
##~~ EventHandlerPlugin
|
||||
|
||||
def on_event(self, event, payload):
|
||||
from octoprint.events import Events
|
||||
if event != Events.CONNECTIVITY_CHANGED or not payload or not payload.get("new", False):
|
||||
return
|
||||
self._fetch_all_channels_async()
|
||||
|
||||
# Internal Tools
|
||||
|
||||
def _mark_read_until(self, channel, until):
|
||||
|
|
@ -266,6 +275,11 @@ class AnnouncementPlugin(octoprint.plugin.AssetPlugin,
|
|||
safe_key = self._slugify(key)
|
||||
return self._get_channel_configs(force=force).get(safe_key)
|
||||
|
||||
def _fetch_all_channels_async(self, force=False):
|
||||
thread = threading.Thread(target=self._fetch_all_channels, kwargs=dict(force=force))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
def _fetch_all_channels(self, force=False):
|
||||
"""Fetch all channel feeds from cache or network."""
|
||||
|
||||
|
|
@ -298,7 +312,10 @@ class AnnouncementPlugin(octoprint.plugin.AssetPlugin,
|
|||
|
||||
if data is None:
|
||||
# cache not allowed or empty, fetch from network
|
||||
data = self._get_channel_data_from_network(key, config)
|
||||
if self._connectivity_checker.online:
|
||||
data = self._get_channel_data_from_network(key, config)
|
||||
else:
|
||||
self._logger.info("Looks like we are offline, can't fetch announcements for channel {} from network".format(key))
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
|||
|
|
@ -317,7 +317,13 @@ $(function() {
|
|||
self.announcementDialog = $("#plugin_announcements_dialog");
|
||||
self.announcementDialogContent = $("#plugin_announcements_dialog_content");
|
||||
self.announcementDialogTabs = $("#plugin_announcements_dialog_tabs");
|
||||
};
|
||||
|
||||
self.onEventConnectivityChanged = function(payload) {
|
||||
if (!payload || !payload.new) return;
|
||||
self.retrieveData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// view model class, parameters for constructor, container to bind to
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
octoprint.plugin.AssetPlugin,
|
||||
octoprint.plugin.SettingsPlugin,
|
||||
octoprint.plugin.StartupPlugin,
|
||||
octoprint.plugin.BlueprintPlugin):
|
||||
octoprint.plugin.BlueprintPlugin,
|
||||
octoprint.plugin.EventHandlerPlugin):
|
||||
|
||||
ARCHIVE_EXTENSIONS = (".zip", ".tar.gz", ".tgz", ".tar")
|
||||
|
||||
|
|
@ -100,13 +101,7 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
self._console_logger.propagate = False
|
||||
|
||||
# decouple repository fetching from server startup
|
||||
def fetch_data():
|
||||
self._repository_available = self._fetch_repository_from_disk()
|
||||
self._notices_available = self._fetch_notices_from_disk()
|
||||
|
||||
thread = threading.Thread(target=fetch_data)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
self._fetch_all_data(async=True)
|
||||
|
||||
##~~ SettingsPlugin
|
||||
|
||||
|
|
@ -197,6 +192,14 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
except Exception as e:
|
||||
self._logger.warn("Could not remove temporary file {path} again: {message}".format(path=archive.name, message=str(e)))
|
||||
|
||||
##~~ EventHandlerPlugin
|
||||
|
||||
def on_event(self, event, payload):
|
||||
from octoprint.events import Events
|
||||
if event != Events.CONNECTIVITY_CHANGED or not payload or not payload.get("new", False):
|
||||
return
|
||||
self._fetch_all_data(async=True)
|
||||
|
||||
##~~ SimpleApiPlugin
|
||||
|
||||
def get_api_commands(self):
|
||||
|
|
@ -239,7 +242,8 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
additional_args=self._settings.get(["pip_args"]),
|
||||
python=sys.executable
|
||||
),
|
||||
safe_mode=safe_mode)
|
||||
safe_mode=safe_mode,
|
||||
online=self._connectivity_checker.online)
|
||||
|
||||
def etag():
|
||||
import hashlib
|
||||
|
|
@ -250,6 +254,7 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
hash.update(str(self._notices_available))
|
||||
hash.update(repr(self._notices))
|
||||
hash.update(repr(safe_mode))
|
||||
hash.update(repr(self._connectivity_checker.online))
|
||||
return hash.hexdigest()
|
||||
|
||||
def condition():
|
||||
|
|
@ -679,6 +684,18 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
elif (plugin.enabled or getattr(plugin, "safe_mode_enabled", False)) and plugin.key not in self._pending_disable:
|
||||
self._pending_disable.add(plugin.key)
|
||||
|
||||
def _fetch_all_data(self, async=False):
|
||||
def run():
|
||||
self._repository_available = self._fetch_repository_from_disk()
|
||||
self._notices_available = self._fetch_notices_from_disk()
|
||||
|
||||
if async:
|
||||
thread = threading.Thread(target=run)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
else:
|
||||
run()
|
||||
|
||||
def _fetch_repository_from_disk(self):
|
||||
repo_data = None
|
||||
if os.path.isfile(self._repository_cache_path):
|
||||
|
|
@ -696,6 +713,10 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
return self._refresh_repository(repo_data=repo_data)
|
||||
|
||||
def _fetch_repository_from_url(self):
|
||||
if not self._connectivity_checker.online:
|
||||
self._logger.info("Looks like we are offline, can't fetch repository from network")
|
||||
return None
|
||||
|
||||
repository_url = self._settings.get(["repository"])
|
||||
try:
|
||||
r = requests.get(repository_url, timeout=30)
|
||||
|
|
@ -758,13 +779,17 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
|
|||
import json
|
||||
with open(self._notices_cache_path) as f:
|
||||
notice_data = json.load(f)
|
||||
self._logger.info("Loaded notices from disk, was still valid")
|
||||
self._logger.info("Loaded notice data from disk, was still valid")
|
||||
except:
|
||||
self._logger.exception("Error while loading notices from {}".format(self._notices_cache_path))
|
||||
|
||||
return self._refresh_notices(notice_data=notice_data)
|
||||
|
||||
def _fetch_notices_from_url(self):
|
||||
if not self._connectivity_checker.online:
|
||||
self._logger.info("Looks like we are offline, can't fetch notices from network")
|
||||
return None
|
||||
|
||||
notices_url = self._settings.get(["notices"])
|
||||
try:
|
||||
r = requests.get(notices_url, timeout=30)
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ $(function() {
|
|||
self.pipPython = ko.observable();
|
||||
|
||||
self.safeMode = ko.observable();
|
||||
self.online = ko.observable();
|
||||
|
||||
self.pipUseUserString = ko.pureComputed(function() {
|
||||
return self.pipUseUser() ? "yes" : "no";
|
||||
|
|
@ -234,7 +235,7 @@ $(function() {
|
|||
};
|
||||
|
||||
self.enableRepoInstall = function(data) {
|
||||
return self.enableManagement() && self.pipAvailable() && !self.safeMode() && self.isCompatible(data);
|
||||
return self.enableManagement() && self.pipAvailable() && !self.safeMode() && self.online() && self.isCompatible(data);
|
||||
};
|
||||
|
||||
self.invalidUrl = ko.pureComputed(function() {
|
||||
|
|
@ -244,7 +245,7 @@ $(function() {
|
|||
|
||||
self.enableUrlInstall = ko.pureComputed(function() {
|
||||
var url = self.installUrl();
|
||||
return self.enableManagement() && self.pipAvailable() && !self.safeMode() && url !== undefined && url.trim() != "" && !self.invalidUrl();
|
||||
return self.enableManagement() && self.pipAvailable() && !self.safeMode() && self.online() && url !== undefined && url.trim() != "" && !self.invalidUrl();
|
||||
});
|
||||
|
||||
self.invalidArchive = ko.pureComputed(function() {
|
||||
|
|
@ -321,6 +322,7 @@ $(function() {
|
|||
self._fromPipResponse(data.pip, options);
|
||||
|
||||
self.safeMode(data.safe_mode || false);
|
||||
self.online(data.online !== undefined ? data.online : true);
|
||||
};
|
||||
|
||||
self._fromPluginsResponse = function(data, options) {
|
||||
|
|
@ -1020,6 +1022,11 @@ $(function() {
|
|||
self._closeAllNotifications();
|
||||
};
|
||||
|
||||
self.onEventConnectivityChanged = function(payload) {
|
||||
if (!payload || !payload.new) return;
|
||||
self.requestData({eval_notices: true});
|
||||
};
|
||||
|
||||
self._closeAllNotifications = function() {
|
||||
if (self.notifications) {
|
||||
_.each(self.notifications, function(notification) {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,13 @@
|
|||
{% endtrans %}</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro pluginmanager_offline() %}
|
||||
<div class="alert" data-bind="visible: !online()">{% trans %}
|
||||
It looks like OctoPrint has currently no connection to the internet. Due to that it's not possible
|
||||
to install new plugins from the plugin repository or archive URLs.
|
||||
{% endtrans %}</div>
|
||||
{% endmacro %}
|
||||
|
||||
{{ pluginmanager_printing() }}
|
||||
{{ pluginmanager_nopip() }}
|
||||
{{ pluginmanager_safemode() }}
|
||||
|
|
@ -124,6 +131,7 @@
|
|||
{{ pluginmanager_printing() }}
|
||||
{{ pluginmanager_nopip() }}
|
||||
{{ pluginmanager_safemode() }}
|
||||
{{ pluginmanager_offline() }}
|
||||
<h4 style="position: relative">
|
||||
{{ _('... from the <a href="%(url)s" target="_blank">Plugin Repository</a>', url='http://plugins.octoprint.org') }}
|
||||
<div class="dropdown pull-right">
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
octoprint.plugin.AssetPlugin,
|
||||
octoprint.plugin.TemplatePlugin,
|
||||
octoprint.plugin.StartupPlugin,
|
||||
octoprint.plugin.WizardPlugin):
|
||||
octoprint.plugin.WizardPlugin,
|
||||
octoprint.plugin.EventHandlerPlugin):
|
||||
|
||||
COMMIT_TRACKING_TYPES = ("github_commit", "bitbucket_commit")
|
||||
|
||||
|
|
@ -47,8 +48,9 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
self._configured_checks = None
|
||||
self._refresh_configured_checks = False
|
||||
|
||||
self._get_versions_mutex = threading.Lock()
|
||||
self._get_versions_last = None
|
||||
self._get_versions_mutex = threading.RLock()
|
||||
self._get_versions_data = None
|
||||
self._get_versions_data_ready = threading.Event()
|
||||
|
||||
self._version_cache = dict()
|
||||
self._version_cache_ttl = 0
|
||||
|
|
@ -563,6 +565,17 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
checkout_folder = self._get_octoprint_checkout_folder(checks=checks)
|
||||
return check and "update_script" in check and not checkout_folder
|
||||
|
||||
##~~ EventHandlerPlugin API
|
||||
|
||||
def on_event(self, event, payload):
|
||||
from octoprint.events import Events
|
||||
if event != Events.CONNECTIVITY_CHANGED or not payload or not payload.get("new", False):
|
||||
return
|
||||
|
||||
thread = threading.Thread(target=self.get_current_versions)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
#~~ Updater
|
||||
|
||||
def get_current_versions(self, check_targets=None, force=False):
|
||||
|
|
@ -583,6 +596,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
|
||||
# we don't want to do the same work twice, so let's use a lock
|
||||
if self._get_versions_mutex.acquire(False):
|
||||
self._get_versions_data_ready.clear()
|
||||
try:
|
||||
futures_to_result = dict()
|
||||
online = self._connectivity_checker.check_immediately()
|
||||
|
|
@ -657,13 +671,14 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
if self._version_cache_dirty:
|
||||
self._save_version_cache()
|
||||
|
||||
self._get_versions_last = information, update_available, update_possible
|
||||
self._get_versions_data = information, update_available, update_possible
|
||||
self._get_versions_data_ready.set()
|
||||
finally:
|
||||
self._get_versions_mutex.release()
|
||||
|
||||
else: # something's already in progress, let's wait for it to complete and use its result
|
||||
self._get_versions_mutex.wait()
|
||||
information, update_available, update_possible = self._get_versions_last
|
||||
self._get_versions_data_ready.wait()
|
||||
information, update_available, update_possible = self._get_versions_data
|
||||
|
||||
return information, update_available, update_possible
|
||||
|
||||
|
|
@ -708,14 +723,13 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
information, is_current = version_checker.get_latest(target, check, online=online)
|
||||
if information is not None and not is_current:
|
||||
update_available = True
|
||||
except exceptions.CannotCheckOffline:
|
||||
update_possible = False
|
||||
information["needs_online"] = True
|
||||
except exceptions.UnknownCheckType:
|
||||
self._logger.warn("Unknown check type %s for %s" % (check["type"], target))
|
||||
update_possible = False
|
||||
error = "unknown_check"
|
||||
except exceptions.CannotCheckOffline:
|
||||
self._logger.warn("Cannot check %s while we are offline" % (target,))
|
||||
update_possible = False
|
||||
information["needs_online"] = True
|
||||
except exceptions.NetworkError:
|
||||
self._logger.warn("Could not check %s for updates due to a network error" % target)
|
||||
update_possible = False
|
||||
|
|
|
|||
|
|
@ -643,6 +643,11 @@ $(function() {
|
|||
return true;
|
||||
};
|
||||
|
||||
self.onEventConnectivityChanged = function(payload) {
|
||||
if (!payload || !payload.new) return;
|
||||
self.performCheck();
|
||||
};
|
||||
|
||||
self.onDataUpdaterReconnect = function() {
|
||||
if (self.waitingForRestart) {
|
||||
self.waitingForRestart = false;
|
||||
|
|
|
|||
Loading…
Reference in a new issue