diff --git a/src/octoprint/plugins/discovery/__init__.py b/src/octoprint/plugins/discovery/__init__.py index ad05f6bb..f72b3f25 100644 --- a/src/octoprint/plugins/discovery/__init__.py +++ b/src/octoprint/plugins/discovery/__init__.py @@ -91,10 +91,10 @@ def discovery(): response.headers['Content-Type'] = 'application/xml' return response -class DiscoveryPlugin(octoprint.plugin.types.StartupPlugin, - octoprint.plugin.types.ShutdownPlugin, - octoprint.plugin.types.BlueprintPlugin, - octoprint.plugin.types.SettingsPlugin): +class DiscoveryPlugin(octoprint.plugin.StartupPlugin, + octoprint.plugin.ShutdownPlugin, + octoprint.plugin.BlueprintPlugin, + octoprint.plugin.SettingsPlugin): ssdp_multicast_addr = "239.255.255.250" @@ -109,6 +109,7 @@ class DiscoveryPlugin(octoprint.plugin.types.StartupPlugin, # zeroconf self._sd_refs = dict() + self._cnames = dict() # upnp/ssdp self._ssdp_monitor_active = False @@ -215,6 +216,9 @@ class DiscoveryPlugin(octoprint.plugin.types.StartupPlugin, self.logger.info("Registered {name} for {reg_type}".format(**locals())) def zeroconf_unregister(self, reg_type, port): + if not pybonjour: + return + key = (reg_type, port) if not key in self._sd_refs: return diff --git a/src/octoprint/plugins/netconnectd/__init__.py b/src/octoprint/plugins/netconnectd/__init__.py index d66db094..4bc99279 100644 --- a/src/octoprint/plugins/netconnectd/__init__.py +++ b/src/octoprint/plugins/netconnectd/__init__.py @@ -14,7 +14,8 @@ import octoprint.plugin default_settings = { - "socket": "/var/run/netconnectd.sock" + "socket": "/var/run/netconnectd.sock", + "hostname": None } s = octoprint.plugin.plugin_settings("netconnectd", defaults=default_settings) @@ -28,20 +29,31 @@ class NetconnectdSettingsPlugin(octoprint.plugin.SettingsPlugin, self.logger = logging.getLogger("plugins.netconnectd." + __name__) self.address = s.get(["socket"]) + @property + def hostname(self): + if s.get(["hostname"]): + return s.get(["hostname"]) + else: + import socket + return socket.gethostname() + ".local" + ##~~ SettingsPlugin def on_settings_load(self): return { - "socket": s.get(["socket"]) + "socket": s.get(["socket"]), + "hostname": s.get(["hostname"]) } def on_settings_save(self, data): if "socket" in data and data["socket"]: s.set(["socket"], data["socket"]) + if "hostname" in data and data["hostname"]: + s.set(["hostname"], data["hostname"]) self.address = s.get(["socket"]) - ##~~ TemplatePlugin API (part of SettingsPlugin) + ##~~ TemplatePlugin API def get_template_vars(self): return dict( @@ -70,7 +82,8 @@ class NetconnectdSettingsPlugin(octoprint.plugin.SettingsPlugin, return jsonify({ "wifis": wifis, - "status": status + "status": status, + "hostname": self.hostname }) def on_api_command(self, command, data): @@ -153,6 +166,7 @@ class NetconnectdSettingsPlugin(octoprint.plugin.SettingsPlugin, import socket sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.settimeout(10) try: sock.connect(self.address) sock.sendall(js + '\x00') diff --git a/src/octoprint/plugins/netconnectd/static/js/netconnectd.js b/src/octoprint/plugins/netconnectd/static/js/netconnectd.js index ba69fb5e..1be18507 100644 --- a/src/octoprint/plugins/netconnectd/static/js/netconnectd.js +++ b/src/octoprint/plugins/netconnectd/static/js/netconnectd.js @@ -8,8 +8,12 @@ $(function() { self.pollingEnabled = false; self.pollingTimeoutId = undefined; + self.reconnectInProgress = false; + self.reconnectTimeout = undefined; + self.enableQualitySorting = ko.observable(false); + self.hostname = ko.observable(); self.status = { link: ko.observable(), connections: { @@ -32,17 +36,16 @@ $(function() { return self.editorWifiPassphrase1() != self.editorWifiPassphrase2(); }); - self.working = ko.observable(false); self.error = ko.observable(false); self.connectionStateText = ko.computed(function() { if (self.error()) { return gettext("Error while talking to netconnectd, is the service running?"); + } else if (self.status.connections.ap()) { + return gettext("Acting as access point"); } else if (self.status.link()) { - if (self.status.connections.ap()) { - return gettext("Acting as access point"); - } else if (self.status.connections.wired()) { + if (self.status.connections.wired()) { return gettext("Connected via wire"); } else if (self.status.connections.wifi()) { if (self.status.wifi.current_ssid()) { @@ -84,7 +87,7 @@ $(function() { ); self.getEntryId = function(data) { - return "settings_plugin_netconnectd_connectbutton_" + md5(data.ssid); + return "settings_plugin_netconnectd_wifi_" + md5(data.ssid); }; self.refresh = function() { @@ -99,6 +102,8 @@ $(function() { self.error(false); } + self.hostname(response.hostname); + self.status.link(response.status.link); self.status.connections.ap(response.status.connections.ap); self.status.connections.wifi(response.status.connections.wifi); @@ -106,7 +111,6 @@ $(function() { self.status.wifi.current_ssid(response.status.wifi.current_ssid); self.status.wifi.current_address(response.status.wifi.current_address); - self.statusCurrentWifi(undefined); if (response.status.wifi.current_ssid && response.status.wifi.current_address) { _.each(response.wifis, function(wifi) { @@ -195,15 +199,52 @@ $(function() { self.sendWifiConfig = function(ssid, psk, successCallback, failureCallback) { self.working(true); + if (self.status.connections.ap()) { + self.reconnectInProgress = true; + + var reconnectText = gettext("OctoPrint is now switching to your configured Wifi connection and therefore shutting down the Access Point. I'm continuously trying to reach it at %(hostname)s but it might take a while. If you are not reconnected over the next couple of minutes, please try to reconnect to OctoPrint manually because then I was unable to find it myself."); + + showOfflineOverlay( + gettext("Reconnecting..."), + _.sprintf(reconnectText, {hostname: self.hostname()}), + self.tryReconnect + ); + } self._postCommand("configure_wifi", {ssid: ssid, psk: psk}, successCallback, failureCallback, function() { self.working(false); - }); + if (self.reconnectInProgress) { + self.tryReconnect(); + } + }, 5000); }; - self._postCommand = function (command, data, successCallback, failureCallback, alwaysCallback) { + self.tryReconnect = function() { + var hostname = self.hostname(); + + var location = window.location.href + location = location.replace(location.match("https?\\://([^:@]+(:[^@]+)?@)?([^:/]+)")[3], hostname); + + var pingCallback = function(result) { + if (!result) { + return; + } + + if (self.reconnectTimeout != undefined) { + clearTimeout(self.reconnectTimeout); + window.location.replace(location); + } + hideOfflineOverlay(); + self.reconnectInProgress = false; + }; + + ping(location, pingCallback); + self.reconnectTimeout = setTimeout(self.tryReconnect, 1000); + }; + + self._postCommand = function (command, data, successCallback, failureCallback, alwaysCallback, timeout) { var payload = _.extend(data, {command: command}); - $.ajax({ + var params = { url: API_BASEURL + "plugin/netconnectd", type: "POST", dataType: "json", @@ -218,7 +259,13 @@ $(function() { complete: function() { if (alwaysCallback) alwaysCallback(); } - }); + }; + + if (timeout != undefined) { + params.timeout = timeout; + } + + $.ajax(params); }; self.requestData = function () { @@ -254,6 +301,10 @@ $(function() { self.pollingTimeoutId = undefined; } self.pollingEnabled = false; + }; + + self.onServerDisconnect = function() { + return !self.reconnectInProgress; } } diff --git a/src/octoprint/server/api/__init__.py b/src/octoprint/server/api/__init__.py index 910b14d7..bab0cdd7 100644 --- a/src/octoprint/server/api/__init__.py +++ b/src/octoprint/server/api/__init__.py @@ -114,7 +114,7 @@ def afterApiRequests(resp): def pluginData(name): api_plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.SimpleApiPlugin) if not name in api_plugins: - make_response(404) + return make_response("Not found", 404) api_plugin = api_plugins[name] response = api_plugin.on_api_get(request) @@ -130,12 +130,12 @@ def pluginData(name): def pluginCommand(name): api_plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.SimpleApiPlugin) if not name in api_plugins: - return make_response(404) + return make_response("Not found", 404) api_plugin = api_plugins[name] valid_commands = api_plugin.get_api_commands() if valid_commands is None: - return make_response(405) + return make_response("Method not allowed", 405) command, data, response = util.getJsonCommandFromRequest(request, valid_commands) if response is not None: diff --git a/src/octoprint/static/js/app/dataupdater.js b/src/octoprint/static/js/app/dataupdater.js index 177cef78..6f6fedb5 100644 --- a/src/octoprint/static/js/app/dataupdater.js +++ b/src/octoprint/static/js/app/dataupdater.js @@ -31,9 +31,28 @@ function DataUpdater(allViewModels) { }; self._onclose = function() { - $("#offline_overlay_message").html(gettext("The server appears to be offline, at least I'm not getting any response from it. I'll try to reconnect automatically over the next couple of minutes, however you are welcome to try a manual reconnect anytime using the button below.")); - if (!$("#offline_overlay").is(":visible")) - $("#offline_overlay").show(); + var handled = false; + _.each(self.allViewModels, function(viewModel) { + if (handled == true) { + return; + } + + if (viewModel.hasattr("onServerDisconnect")) { + if (!viewModel.onServerDisconnect()) { + handled = true; + } + } + }); + + if (handled) { + return; + } + + showOfflineOverlay( + gettext("Server is offline"), + gettext("The server appears to be offline, at least I'm not getting any response from it. I'll try to reconnect automatically over the next couple of minutes, however you are welcome to try a manual reconnect anytime using the button below."), + self.reconnect + ); if (self._autoReconnectTrial < self._autoReconnectTimeouts.length) { var timeout = self._autoReconnectTimeouts[self._autoReconnectTrial]; @@ -46,6 +65,24 @@ function DataUpdater(allViewModels) { }; self._onreconnectfailed = function() { + var handled = false; + _.each(self.allViewModels, function(viewModel) { + if (handled == true) { + return; + } + + if (viewModel.hasattr("onServerDisconnect")) { + if (!viewModel.onServerDisconnect()) { + handled = true; + } + } + }); + + if (handled) { + return; + } + + $("#offline_overlay_title").text(gettext("Server is offline")); $("#offline_overlay_message").html(gettext("The server appears to be offline, at least I'm not getting any response from it. I could not reconnect automatically, but you may try a manual reconnect using the button below.")); }; @@ -70,7 +107,7 @@ function DataUpdater(allViewModels) { $("span.version").text(DISPLAY_VERSION); if ($("#offline_overlay").is(":visible")) { - $("#offline_overlay").hide(); + hideOfflineOverlay(); _.each(self.allViewModels, function(viewModel) { if (viewModel.hasOwnProperty("onDataUpdaterReconnect")) { viewModel.onDataUpdaterReconnect(); diff --git a/src/octoprint/static/js/app/helpers.js b/src/octoprint/static/js/app/helpers.js index 5395dd29..a67ad407 100644 --- a/src/octoprint/static/js/app/helpers.js +++ b/src/octoprint/static/js/app/helpers.js @@ -359,3 +359,42 @@ function pnotifyAdditionalInfo(inner) { + '
' + inner + '
' + ''; } + +function ping(url, callback) { + var img = new Image(); + var calledBack = false; + + img.onload = function() { + callback(true); + calledBack = true; + }; + img.onerror = function() { + if (!calledBack) { + callback(true); + calledBack = true; + } + }; + img.src = url; + setTimeout(function() { + if (!calledBack) { + callback(false); + calledBack = true; + } + }, 1500); +} + +function showOfflineOverlay(title, message, reconnectCallback) { + if (title == undefined) { + title = gettext("Server is offline"); + } + + $("#offline_overlay_title").text(title); + $("#offline_overlay_message").html(message); + $("#offline_overlay_reconnect").click(reconnectCallback); + if (!$("#offline_overlay").is(":visible")) + $("#offline_overlay").show(); +} + +function hideOfflineOverlay() { + $("#offline_overlay").hide(); +} diff --git a/src/octoprint/static/js/app/main.js b/src/octoprint/static/js/app/main.js index d81cd623..21e60446 100644 --- a/src/octoprint/static/js/app/main.js +++ b/src/octoprint/static/js/app/main.js @@ -331,9 +331,6 @@ $(function() { }, 100); }); - //~~ Offline overlay - $("#offline_overlay_reconnect").click(function() {dataUpdater.reconnect()}); - //~~ Underscore setup _.mixin(_.str.exports()); diff --git a/src/octoprint/templates/dialogs.jinja2 b/src/octoprint/templates/dialogs.jinja2 index 8d4c73fd..95b74e41 100644 --- a/src/octoprint/templates/dialogs.jinja2 +++ b/src/octoprint/templates/dialogs.jinja2 @@ -3,7 +3,7 @@
-

{{ _('Server is offline') }}

+

{{ _('Server is offline') }}

{{ _('Attempt to reconnect') }}