gui: Remove probing for remote GUI address (ref #7017) (#7136)

This commit is contained in:
Jakob Borg 2020-11-24 22:07:22 +01:00 committed by GitHub
parent e5c1948b94
commit 6864f7c9d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 168 deletions

View File

@ -234,6 +234,7 @@
"Release Notes": "Release Notes",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.",
"Remote Devices": "Remote Devices",
"Remote GUI": "Remote GUI",
"Remove": "Remove",
"Remove Device": "Remove Device",
"Remove Folder": "Remove Folder",

View File

@ -806,8 +806,8 @@
<th><span class="fas fa-fw fa-desktop"></span>&nbsp;<span translate>Remote GUI</span></th>
<td class="text-right" ng-attr-title="Port {{deviceCfg.remoteGUIPort}}">
<!-- Apply RFC6874 encoding for IPv6 link-local zone identifier -->
<a ng-if="idToRemoteGUI[deviceCfg.deviceID]" href="{{idToRemoteGUI[deviceCfg.deviceID].replace('%', '%25')}}">{{idToRemoteGUI[deviceCfg.deviceID]}}</a>
<span ng-if="!idToRemoteGUI[deviceCfg.deviceID]">Unreachable</span>
<a ng-if="hasRemoteGUIAddress(deviceCfg)" href="{{remoteGUIAddress(deviceCfg).replace('%', '%25')}}">{{remoteGUIAddress(deviceCfg)}}</a>
<span translate ng-if="!hasRemoteGUIAddress(deviceCfg)">Unknown</span>
</td>
</tr>
</tbody>

View File

@ -24,9 +24,6 @@ angular.module('syncthing.core')
$scope.config = {};
$scope.configInSync = true;
$scope.connections = {};
$scope.idToRemoteGUI = {};
$scope.remoteGUICache = {};
$scope.showRemoteGUI = true;
$scope.errors = [];
$scope.model = {};
$scope.myID = '';
@ -64,10 +61,6 @@ angular.module('syncthing.core')
$scope.metricRates = (window.localStorage["metricRates"] == "true");
} catch (exception) { }
if ("showRemoteGUI" in window.localStorage) {
$scope.showRemoteGUI = (window.localStorage["showRemoteGUI"] == "true");
}
$scope.folderDefaults = {
devices: [],
type: "sendreceive",
@ -382,7 +375,6 @@ angular.module('syncthing.core')
$scope.config.options._globalAnnounceServersStr = $scope.config.options.globalAnnounceServers.join(', ');
$scope.config.options._urAcceptedStr = "" + $scope.config.options.urAccepted;
$scope.config.gui["showRemoteGUI"] = $scope.showRemoteGUI;
$scope.devices = deviceMap($scope.config.devices);
for (var id in $scope.devices) {
$scope.completion[id] = {
@ -525,16 +517,6 @@ angular.module('syncthing.core')
console.log("recalcCompletion", device, $scope.completion[device]);
}
function replaceAddressPort(address, newPort) {
var lastColonIndex = address.length;
for (var index = 0; index < address.length; index++) {
if (address[index] === ":") {
lastColonIndex = index;
}
}
return address.substr(0, lastColonIndex) + ":" + newPort.toString();
}
function refreshCompletion(device, folder) {
if (device === $scope.myID) {
return;
@ -581,50 +563,9 @@ angular.module('syncthing.core')
}
$scope.connections = data;
console.log("refreshConnections", data);
refreshRemoteGUI(data);
}).error($scope.emitHTTPError);
}
function refreshRemoteGUI(connections) {
if (!$scope.showRemoteGUI) {
$scope.idToRemoteGUI = {}
return
}
var newCache = {};
for (var id in connections) {
if (!(id in $scope.devices)) {
// Avoid errors when called before first updateLocalConfig()
continue;
}
var port = $scope.devices[id].remoteGUIPort;
if (port <= 0
|| !connections[id].address
|| connections[id].type.includes("relay")) {
// Relay connections never work as desired here, nor incomplete addresses
$scope.idToRemoteGUI[id] = "";
continue;
}
var newAddress = "http://" + replaceAddressPort(connections[id].address, port);
if (!(newAddress in $scope.remoteGUICache)) {
// No cached result, trigger a new port probing asynchronously
$scope.probeRemoteGUIAddress(id, newAddress);
} else {
newCache[newAddress] = $scope.remoteGUICache[newAddress];
// Copy cached probing result in the corner case of duplicate GUI
// addresses for different devices. Which is useless, but
// possible when behind the same NAT router.
if (newCache[newAddress]) {
$scope.idToRemoteGUI[id] = newAddress;
} else {
$scope.idToRemoteGUI[id] = "";
}
}
}
// Replace the cache to discard stale addresses
$scope.remoteGUICache = newCache;
}
function refreshErrors() {
$http.get(urlbase + '/system/error').success(function (data) {
$scope.errors = data.errors;
@ -643,22 +584,6 @@ angular.module('syncthing.core')
}).error($scope.emitHTTPError);
}
$scope.probeRemoteGUIAddress = function (deviceId, address) {
// Strip off possible IPv6 link-local zone identifier, as Angular chokes on it
// with an (ugly, unjustified) console error message.
var urlAddress = address.replace(/%[a-zA-Z0-9_\.\-]*\]/, ']');
$http({
method: "OPTIONS",
url: urlAddress,
}).success(function (data) {
$scope.remoteGUICache[address] = true;
$scope.idToRemoteGUI[deviceId] = address;
}).error(function (err) {
$scope.remoteGUICache[address] = false;
$scope.idToRemoteGUI[deviceId] = "";
});
}
$scope.refreshNeed = function (page, perpage) {
if (!$scope.neededFolder) {
return;
@ -1140,6 +1065,28 @@ angular.module('syncthing.core')
return '?';
};
$scope.hasRemoteGUIAddress = function (deviceCfg) {
if (!deviceCfg.remoteGUIPort)
return false;
var conn = $scope.connections[deviceCfg.deviceID];
return conn && conn.connected && conn.address && conn.type.indexOf('Relay') == -1;
};
$scope.remoteGUIAddress = function (deviceCfg) {
// Assume hasRemoteGUIAddress is true or we would not be here
var conn = $scope.connections[deviceCfg.deviceID];
return 'http://' + replaceAddressPort(conn.address, deviceCfg.remoteGUIPort);
};
function replaceAddressPort(address, newPort) {
for (var index = address.length - 1; index >= 0; index--) {
if (address[index] === ":") {
return address.substr(0, index) + ":" + newPort.toString();
}
}
return address;
}
$scope.friendlyNameFromShort = function (shortID) {
var matches = Object.keys($scope.devices).filter(function (id) {
return id.substr(0, 7) === shortID;
@ -1317,11 +1264,6 @@ angular.module('syncthing.core')
};
$scope.saveConfig = function (callback) {
// set local storage feature and delete from post request
window.localStorage.setItem("showRemoteGUI", $scope.config.gui.showRemoteGUI ? "true" : "false");
$scope.showRemoteGUI = $scope.config.gui.showRemoteGUI;
delete $scope.config.gui.showRemoteGUI;
var cfg = JSON.stringify($scope.config);
var opts = {
headers: {

View File

@ -818,8 +818,8 @@
<th><span class="fas fa-fw fa-desktop"></span>&nbsp;<span translate>Remote GUI</span></th>
<td class="text-right" ng-attr-title="Port {{deviceCfg.remoteGUIPort}}">
<!-- Apply RFC6874 encoding for IPv6 link-local zone identifier -->
<a ng-if="idToRemoteGUI[deviceCfg.deviceID]" href="{{idToRemoteGUI[deviceCfg.deviceID].replace('%', '%25')}}">{{idToRemoteGUI[deviceCfg.deviceID]}}</a>
<span ng-if="!idToRemoteGUI[deviceCfg.deviceID]">Unreachable</span>
<a ng-if="hasRemoteGUIAddress(deviceCfg)" href="{{remoteGUIAddress(deviceCfg).replace('%', '%25')}}">{{remoteGUIAddress(deviceCfg)}}</a>
<span translate ng-if="!hasRemoteGUIAddress(deviceCfg)">Unknown</span>
</td>
</tr>
</tbody>

View File

@ -24,9 +24,6 @@ angular.module('syncthing.core')
$scope.config = {};
$scope.configInSync = true;
$scope.connections = {};
$scope.idToRemoteGUI = {};
$scope.remoteGUICache = {};
$scope.showRemoteGUI = true;
$scope.errors = [];
$scope.model = {};
$scope.myID = '';
@ -64,10 +61,6 @@ angular.module('syncthing.core')
$scope.metricRates = (window.localStorage["metricRates"] == "true");
} catch (exception) { }
if ("showRemoteGUI" in window.localStorage) {
$scope.showRemoteGUI = (window.localStorage["showRemoteGUI"] == "true");
}
$scope.folderDefaults = {
devices: [],
type: "sendreceive",
@ -382,7 +375,6 @@ angular.module('syncthing.core')
$scope.config.options._globalAnnounceServersStr = $scope.config.options.globalAnnounceServers.join(', ');
$scope.config.options._urAcceptedStr = "" + $scope.config.options.urAccepted;
$scope.config.gui["showRemoteGUI"] = $scope.showRemoteGUI;
$scope.devices = deviceMap($scope.config.devices);
for (var id in $scope.devices) {
$scope.completion[id] = {
@ -525,16 +517,6 @@ angular.module('syncthing.core')
console.log("recalcCompletion", device, $scope.completion[device]);
}
function replaceAddressPort(address, newPort) {
var lastColonIndex = address.length;
for (var index = 0; index < address.length; index++) {
if (address[index] === ":") {
lastColonIndex = index;
}
}
return address.substr(0, lastColonIndex) + ":" + newPort.toString();
}
function refreshCompletion(device, folder) {
if (device === $scope.myID) {
return;
@ -581,50 +563,9 @@ angular.module('syncthing.core')
}
$scope.connections = data;
console.log("refreshConnections", data);
refreshRemoteGUI(data);
}).error($scope.emitHTTPError);
}
function refreshRemoteGUI(connections) {
if (!$scope.showRemoteGUI) {
$scope.idToRemoteGUI = {}
return
}
var newCache = {};
for (var id in connections) {
if (!(id in $scope.devices)) {
// Avoid errors when called before first updateLocalConfig()
continue;
}
var port = $scope.devices[id].remoteGUIPort;
if (port <= 0
|| !connections[id].address
|| connections[id].type.includes("relay")) {
// Relay connections never work as desired here, nor incomplete addresses
$scope.idToRemoteGUI[id] = "";
continue;
}
var newAddress = "http://" + replaceAddressPort(connections[id].address, port);
if (!(newAddress in $scope.remoteGUICache)) {
// No cached result, trigger a new port probing asynchronously
$scope.probeRemoteGUIAddress(id, newAddress);
} else {
newCache[newAddress] = $scope.remoteGUICache[newAddress];
// Copy cached probing result in the corner case of duplicate GUI
// addresses for different devices. Which is useless, but
// possible when behind the same NAT router.
if (newCache[newAddress]) {
$scope.idToRemoteGUI[id] = newAddress;
} else {
$scope.idToRemoteGUI[id] = "";
}
}
}
// Replace the cache to discard stale addresses
$scope.remoteGUICache = newCache;
}
function refreshErrors() {
$http.get(urlbase + '/system/error').success(function (data) {
$scope.errors = data.errors;
@ -643,23 +584,6 @@ angular.module('syncthing.core')
}).error($scope.emitHTTPError);
}
$scope.probeRemoteGUIAddress = function (deviceId, address) {
// Strip off possible IPv6 link-local zone identifier, as Angular chokes on it
// with an (ugly, unjustified) console error message.
var urlAddress = address.replace(/%[a-zA-Z0-9_\.\-]*\]/, ']');
console.log(urlAddress);
$http({
method: "OPTIONS",
url: urlAddress,
}).success(function (data) {
$scope.remoteGUICache[address] = true;
$scope.idToRemoteGUI[deviceId] = address;
}).error(function (err) {
$scope.remoteGUICache[address] = false;
$scope.idToRemoteGUI[deviceId] = "";
});
}
$scope.refreshNeed = function (page, perpage) {
if (!$scope.neededFolder) {
return;
@ -1145,6 +1069,28 @@ angular.module('syncthing.core')
return '?';
};
$scope.hasRemoteGUIAddress = function (deviceCfg) {
if (!deviceCfg.remoteGUIPort)
return false;
var conn = $scope.connections[deviceCfg.deviceID];
return conn && conn.connected && conn.address && conn.type.indexOf('Relay') == -1;
};
$scope.remoteGUIAddress = function (deviceCfg) {
// Assume hasRemoteGUIAddress is true or we would not be here
var conn = $scope.connections[deviceCfg.deviceID];
return 'http://' + replaceAddressPort(conn.address, deviceCfg.remoteGUIPort);
};
function replaceAddressPort(address, newPort) {
for (var index = address.length - 1; index >= 0; index--) {
if (address[index] === ":") {
return address.substr(0, index) + ":" + newPort.toString();
}
}
return address;
}
$scope.friendlyNameFromShort = function (shortID) {
var matches = Object.keys($scope.devices).filter(function (id) {
return id.substr(0, 7) === shortID;
@ -1322,11 +1268,6 @@ angular.module('syncthing.core')
};
$scope.saveConfig = function (callback) {
// set local storage feature and delete from post request
window.localStorage.setItem("showRemoteGUI", $scope.config.gui.showRemoteGUI ? "true" : "false");
$scope.showRemoteGUI = $scope.config.gui.showRemoteGUI;
delete $scope.config.gui.showRemoteGUI;
var cfg = JSON.stringify($scope.config);
var opts = {
headers: {