+
+
+
+
+
Connection lost
+
+ The connection to the server is lost, attempting again in {{ state.connectionAttemptTimer + 1000 | timeremaining }} ...
+
+
+ Connnecting to server ...
+
+
+
+
diff --git a/Duplicati/Server/webroot/ngax/scripts/controllers/AppController.js b/Duplicati/Server/webroot/ngax/scripts/controllers/AppController.js
index 8c0e05e6c..837c33862 100644
--- a/Duplicati/Server/webroot/ngax/scripts/controllers/AppController.js
+++ b/Duplicati/Server/webroot/ngax/scripts/controllers/AppController.js
@@ -2,4 +2,8 @@ backupApp.controller('AppController', function($scope, BrandingService, ServerSt
$scope.appName = BrandingService.appName;
$scope.state = ServerStatus.watch($scope);
$scope.localized = {};
+
+ $scope.doReconnect = function() {
+ ServerStatus.reconnect();
+ };
});
\ No newline at end of file
diff --git a/Duplicati/Server/webroot/ngax/scripts/filters/timeremaining.js b/Duplicati/Server/webroot/ngax/scripts/filters/timeremaining.js
index 7dfbfe85e..964a21295 100644
--- a/Duplicati/Server/webroot/ngax/scripts/filters/timeremaining.js
+++ b/Duplicati/Server/webroot/ngax/scripts/filters/timeremaining.js
@@ -48,6 +48,9 @@ backupApp.filter('timeremaining', function() {
r[i] = v;
};
+ if (r.length == 1)
+ r.unshift('0');
+
return r.join(':');
}
});
\ No newline at end of file
diff --git a/Duplicati/Server/webroot/ngax/scripts/services/ServerStatus.js b/Duplicati/Server/webroot/ngax/scripts/services/ServerStatus.js
index 955d5864e..18e20c5fc 100644
--- a/Duplicati/Server/webroot/ngax/scripts/services/ServerStatus.js
+++ b/Duplicati/Server/webroot/ngax/scripts/services/ServerStatus.js
@@ -15,6 +15,7 @@ backupApp.service('ServerStatus', function($http, $rootScope, $timeout, AppServi
connectionState: 'connected',
xsfrerror: false,
connectionAttemptTimer: 0,
+ failedConnectionAttempts: 0,
lastPgEvent: null
};
@@ -143,7 +144,7 @@ backupApp.service('ServerStatus', function($http, $rootScope, $timeout, AppServi
$rootScope.$broadcast('serverstatechanged');
}
- }, 500);
+ }, 1000);
};
var updatepausetimer = null;
@@ -188,6 +189,7 @@ backupApp.service('ServerStatus', function($http, $rootScope, $timeout, AppServi
var url = '/serverstate/?lasteventid=' + parseInt(state.lastEventId) + '&longpoll=' + (state.lastEventId > 0 ? 'true' : 'false') + '&duration=' + parseInt((longpolltime-1000) / 1000) + 's';
AppService.get(url, {timeout: state.lastEventId > 0 ? longpolltime : 5000}).then(
function (response) {
+ var oldEventId = state.lastEventId;
var anychanged =
notifyIfChanged(response.data, 'LastEventID', 'lastEventId') |
notifyIfChanged(response.data, 'LastDataUpdateID', 'lastDataUpdateId') |
@@ -196,11 +198,18 @@ backupApp.service('ServerStatus', function($http, $rootScope, $timeout, AppServi
notifyIfChanged(response.data, 'ProgramState', 'programState') |
notifyIfChanged(response.data, 'EstimatedPauseEnd', 'estimatedPauseEnd');
+ // Clear error indicators
+ state.failedConnectionAttempts = 0;
+ state.xsfrerror = false;
if (state.connectionState != 'connected') {
state.connectionState = 'connected';
$rootScope.$broadcast('serverstatechanged.connectionState', state.connectionState);
anychanged = true;
+
+ // Reload page, server restarted
+ if (oldEventId > state.lastEventId)
+ location.reload(true);
}
anychanged |= pauseTimerUpdater(true);
@@ -215,20 +224,28 @@ backupApp.service('ServerStatus', function($http, $rootScope, $timeout, AppServi
longpoll();
},
- function(respone) {
- if (state.connectionState == 'connected') {
- // First failure, we ignore
- state.connectionState = 'connecting';
+ function(response) {
+
+ var oldxsfrstate = state.xsfrerror;
+ state.failedConnectionAttempts++;
+ state.xsfrerror = response.statusText.toLowerCase().indexOf('xsrf') >= 0;
+
+ // First failure, we ignore
+ if (state.connectionState == 'connected' && state.failedConnectionAttempts == 1) {
// Try again
longpoll();
} else {
- // Real failure, start countdown
- state.lastEventId = -1;
state.connectionState = 'disconnected';
- countdownForForReLongPoll(longpoll);
+ //If we got a new XSRF token this time, quickly retry
+ if (state.xsfrerror && !oldxsfrstate) {
+ longpoll();
+ } else {
+ // Otherwise, start countdown to next try
+ countdownForForReLongPoll(longpoll);
+ }
}
// Notify
@@ -238,5 +255,7 @@ backupApp.service('ServerStatus', function($http, $rootScope, $timeout, AppServi
);
};
+ this.reconnect = longpoll;
+
longpoll();
});
\ No newline at end of file
diff --git a/Duplicati/Server/webroot/ngax/styles/styles2.css b/Duplicati/Server/webroot/ngax/styles/styles2.css
index bd2c5b398..4bc91fe1a 100644
--- a/Duplicati/Server/webroot/ngax/styles/styles2.css
+++ b/Duplicati/Server/webroot/ngax/styles/styles2.css
@@ -444,3 +444,59 @@ ul.tabs > li.active, ul.tabs > li.active > a {
background-color: lightgray;
color: black;
}
+
+div.connection-lost, div.blocker {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ right: 0px;
+ bottom: 0px;
+ margin: auto;
+}
+
+div.connection-lost {
+ width: 250px;
+ height: 200px;
+}
+
+div.blocker {
+ background-color: #000000;
+ opacity: 0.65;
+}
+
+.connection-lost div.info {
+ display: inline-block;
+}
+
+.connection-lost div.title {
+ border: 1px solid #65b1dd;
+ background-color: #65b1dd;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ border-bottom-left-radius: 0px;
+ border-bottom-right-radius: 0px;
+ padding: 10px;
+ padding-left: 20px;
+ padding-right: 20px;
+ font-weight: bold;
+ color: lightgray;
+ width: 100%;
+ text-align: center;
+}
+
+.connection-lost div.content {
+ background-color: white;
+ border: 1px solid white;
+ padding: 20px;
+ width: 100%;
+ min-width: 250px;
+}
+
+.connection-lost div.content.buttons {
+ padding-bottom: 45px;
+ border-top-left-radius: 0px;
+ border-top-right-radius: 0px;
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+}
+
diff --git a/Duplicati/Server/webroot/ngax/templates/home.html b/Duplicati/Server/webroot/ngax/templates/home.html
index 807294a5b..d0a0c9e93 100644
--- a/Duplicati/Server/webroot/ngax/templates/home.html
+++ b/Duplicati/Server/webroot/ngax/templates/home.html
@@ -34,7 +34,7 @@
-
Scheduled backups:
+
Stored backup jobs: