Try to reconnect to backend when switching from ap to wifi
netconnectd now regularly pings hostname it got from backend (defaults to <systemname>.local) while switching to wifi from ap mode and reloads page to that if host comes up. This requires the browser the client is currently running in to be able to resolve local domains as broadcasted via avahi. Windows systems will need to install the Bonjour for Windows client for this to work.
This commit is contained in:
parent
65263a8b74
commit
d1c34a9c88
8 changed files with 171 additions and 29 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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 <strong>%(hostname)s</strong> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 <strong>over the next couple of minutes</strong>, 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 <strong>over the next couple of minutes</strong>, 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 <strong>could not reconnect automatically</strong>, 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();
|
||||
|
|
|
|||
|
|
@ -359,3 +359,42 @@ function pnotifyAdditionalInfo(inner) {
|
|||
+ '<div class="pnotify_more_container hide">' + inner + '</div>'
|
||||
+ '</div>';
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,9 +331,6 @@ $(function() {
|
|||
}, 100);
|
||||
});
|
||||
|
||||
//~~ Offline overlay
|
||||
$("#offline_overlay_reconnect").click(function() {dataUpdater.reconnect()});
|
||||
|
||||
//~~ Underscore setup
|
||||
|
||||
_.mixin(_.str.exports());
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<div id="offline_overlay_wrapper">
|
||||
<div class="container">
|
||||
<div class="hero-unit">
|
||||
<h1>{{ _('Server is offline') }}</h1>
|
||||
<h1 id="offline_overlay_title">{{ _('Server is offline') }}</h1>
|
||||
<p id="offline_overlay_message"></p>
|
||||
<p>
|
||||
<a class="btn btn-primary btn-large" id="offline_overlay_reconnect">{{ _('Attempt to reconnect') }}</a>
|
||||
|
|
|
|||
Loading…
Reference in a new issue