mirror of https://github.com/keeweb/keeweb.git
app restart on update
This commit is contained in:
parent
a32fc8ef45
commit
9ec30ff533
17
Gruntfile.js
17
Gruntfile.js
|
@ -3,6 +3,9 @@
|
|||
var fs = require('fs'),
|
||||
path = require('path');
|
||||
|
||||
/* jshint node:true */
|
||||
/* jshint browser:false */
|
||||
|
||||
var StringReplacePlugin = require('string-replace-webpack-plugin');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
@ -55,8 +58,8 @@ module.exports = function(grunt) {
|
|||
},
|
||||
clean: {
|
||||
dist: ['dist', 'tmp'],
|
||||
desktop_dist: ['dist/desktop'],
|
||||
desktop_tmp: ['tmp/desktop']
|
||||
'desktop_dist': ['dist/desktop'],
|
||||
'desktop_tmp': ['tmp/desktop']
|
||||
},
|
||||
copy: {
|
||||
html: {
|
||||
|
@ -338,10 +341,12 @@ module.exports = function(grunt) {
|
|||
},
|
||||
compress: {
|
||||
linux: {
|
||||
options: {
|
||||
archive: 'tmp/desktop/KeeWeb.linux.x64.zip'
|
||||
},
|
||||
options: { archive: 'tmp/desktop/KeeWeb.linux.x64.zip' },
|
||||
files: [{ cwd: 'tmp/desktop/KeeWeb-linux-x64', src: '**', expand: true }]
|
||||
},
|
||||
'desktop_update': {
|
||||
options: { archive: 'dist/desktop/UpdateDesktop.zip' },
|
||||
files: [{ cwd: 'tmp/desktop/app', src: '**', expand: true }]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -364,11 +369,13 @@ module.exports = function(grunt) {
|
|||
]);
|
||||
|
||||
grunt.registerTask('desktop', [
|
||||
'default',
|
||||
'gitinfo',
|
||||
'clean:desktop_tmp',
|
||||
'clean:desktop_dist',
|
||||
'copy:desktop_app_content',
|
||||
'string-replace:desktop_html',
|
||||
'compress:desktop_update',
|
||||
'electron',
|
||||
'electron_builder',
|
||||
'compress:linux',
|
||||
|
|
|
@ -46,9 +46,28 @@ if (window.process && window.process.versions && window.process.versions.electro
|
|||
fileExists: function(path) {
|
||||
return this.req('fs').existsSync(path);
|
||||
},
|
||||
preventExit: function(e) {
|
||||
e.returnValue = false;
|
||||
return false;
|
||||
},
|
||||
exit: function() {
|
||||
Launcher.exitRequested = true;
|
||||
this.remReq('app').quit();
|
||||
this.requestExit();
|
||||
},
|
||||
requestExit: function() {
|
||||
var app = this.remReq('app');
|
||||
if (this.restartPending) {
|
||||
app.quitAndRestart();
|
||||
} else {
|
||||
app.quit();
|
||||
}
|
||||
},
|
||||
requestRestart: function() {
|
||||
this.restartPending = true;
|
||||
this.requestExit();
|
||||
},
|
||||
cancelRestart: function() {
|
||||
this.restartPending = false;
|
||||
}
|
||||
};
|
||||
window.launcherOpen = function(path) {
|
||||
|
|
|
@ -10,7 +10,7 @@ var Backbone = require('backbone'),
|
|||
|
||||
var Updater = {
|
||||
UpdateInterval: 1000*60*60*24,
|
||||
MinUpdateTimeout: 500*10,
|
||||
MinUpdateTimeout: 500,
|
||||
MinUpdateSize: 10000,
|
||||
UpdateCheckFiles: ['index.html', 'app.js'],
|
||||
nextCheckTimeout: null,
|
||||
|
@ -18,6 +18,10 @@ var Updater = {
|
|||
enabledAutoUpdate: function() {
|
||||
return Launcher && AppSettingsModel.instance.get('autoUpdate');
|
||||
},
|
||||
updateInProgress: function() {
|
||||
return UpdateModel.instance.get('status') === 'checking' ||
|
||||
['downloading', 'extracting'].indexOf(UpdateModel.instance.get('updateStatus')) >= 0;
|
||||
},
|
||||
init: function() {
|
||||
var willCheckNow = this.scheduleNextCheck();
|
||||
if (!willCheckNow && this.enabledAutoUpdate()) {
|
||||
|
@ -38,11 +42,11 @@ var Updater = {
|
|||
timeDiff = Math.min(Math.max(this.UpdateInterval + (lastCheckDate - new Date()), this.MinUpdateTimeout), this.UpdateInterval);
|
||||
}
|
||||
this.nextCheckTimeout = setTimeout(this.check.bind(this), timeDiff);
|
||||
console.log('Update check will happen in ' + Math.round(timeDiff / 1000) + ' s');
|
||||
console.log('Update check will happen in ' + Math.round(timeDiff / 1000) + 's');
|
||||
return timeDiff === this.MinUpdateTimeout;
|
||||
},
|
||||
check: function(startedByUser) {
|
||||
if (!Launcher) {
|
||||
if (!Launcher || this.updateInProgress()) {
|
||||
return;
|
||||
}
|
||||
UpdateModel.instance.set('status', 'checking');
|
||||
|
@ -72,6 +76,7 @@ var Updater = {
|
|||
that.scheduleNextCheck();
|
||||
return;
|
||||
}
|
||||
var prevLastVersion = UpdateModel.instance.get('lastVersion');
|
||||
UpdateModel.instance.set({
|
||||
status: 'ok',
|
||||
lastCheckDate: dt,
|
||||
|
@ -82,6 +87,11 @@ var Updater = {
|
|||
});
|
||||
UpdateModel.instance.save();
|
||||
that.scheduleNextCheck();
|
||||
if (prevLastVersion === UpdateModel.instance.get('lastVersion') &&
|
||||
UpdateModel.instance.get('updateStatus') === 'ready') {
|
||||
console.log('Waiting for the user to apply downloaded update');
|
||||
return;
|
||||
}
|
||||
that.update(startedByUser);
|
||||
},
|
||||
error: function(e) {
|
||||
|
@ -98,7 +108,7 @@ var Updater = {
|
|||
},
|
||||
update: function(startedByUser) {
|
||||
var ver = UpdateModel.instance.get('lastVersion');
|
||||
if (!Launcher || ver === RuntimeInfo.version || UpdateModel.instance.get('updateStatus')) {
|
||||
if (!Launcher || ver === RuntimeInfo.version) {
|
||||
console.log('You are using the latest version');
|
||||
return;
|
||||
}
|
||||
|
@ -110,15 +120,17 @@ var Updater = {
|
|||
file: 'KeeWeb-' + ver + '.zip',
|
||||
cache: !startedByUser,
|
||||
success: function(filePath) {
|
||||
UpdateModel.instance.set('updateStatus', 'downloaded');
|
||||
console.error('Extracting update file', that.UpdateCheckFiles, filePath);
|
||||
UpdateModel.instance.set('updateStatus', 'extracting');
|
||||
console.log('Extracting update file', that.UpdateCheckFiles, filePath);
|
||||
that.extractAppUpdate(filePath, function(err) {
|
||||
if (err) {
|
||||
console.error('Error extracting update', err);
|
||||
UpdateModel.instance.set({ updateStatus: 'error', updateError: 'Error extracting update' });
|
||||
} else {
|
||||
UpdateModel.instance.set({ updateStatus: 'ready', updateError: null });
|
||||
Backbone.trigger('update-app');
|
||||
if (!startedByUser) {
|
||||
Backbone.trigger('update-app');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -129,7 +141,8 @@ var Updater = {
|
|||
});
|
||||
},
|
||||
|
||||
extractAppUpdate: function(updateFile, expectedFiles, cb) {
|
||||
extractAppUpdate: function(updateFile, cb) {
|
||||
var expectedFiles = this.UpdateCheckFiles;
|
||||
var appPath = Launcher.getUserDataPath();
|
||||
var StreamZip = Launcher.req('node-stream-zip');
|
||||
var zip = new StreamZip({ file: updateFile, storeEntries: true });
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
var Links = {
|
||||
Repo: 'https://github.com/antelle/keeweb',
|
||||
Desktop: 'https://github.com/antelle/keeweb/releases/latest',
|
||||
WebApp: 'https://antelle.github.io/keeweb/',
|
||||
WebApp: 'http://localhost:8088/',
|
||||
License: 'https://github.com/antelle/keeweb/blob/master/MIT-LICENSE.txt',
|
||||
UpdateDesktop: 'https://github.com/antelle/keeweb/releases/download/{ver}/UpdateDesktop.zip'
|
||||
UpdateDesktop: 'http://localhost:8088/releases/download/{ver}/UpdateDesktop.zip'
|
||||
};
|
||||
|
||||
module.exports = Links;
|
||||
|
|
|
@ -22,7 +22,10 @@ var AppSettingsModel = Backbone.Model.extend({
|
|||
try {
|
||||
var data;
|
||||
if (Launcher) {
|
||||
data = JSON.parse(Launcher.readFile(Launcher.getUserDataPath(FileName), 'utf8'));
|
||||
var settingsFile = Launcher.getUserDataPath(FileName);
|
||||
if (Launcher.fileExists(settingsFile)) {
|
||||
data = JSON.parse(Launcher.readFile(settingsFile, 'utf8'));
|
||||
}
|
||||
} else if (typeof localStorage !== 'undefined' && localStorage.appSettings) {
|
||||
data = JSON.parse(localStorage.appSettings);
|
||||
}
|
||||
|
|
|
@ -198,16 +198,25 @@ var AppView = Backbone.View.extend({
|
|||
beforeUnload: function(e) {
|
||||
if (this.model.files.hasUnsavedFiles()) {
|
||||
if (Launcher && !Launcher.exitRequested) {
|
||||
Alerts.yesno({
|
||||
header: 'Unsaved changes!',
|
||||
body: 'You have unsaved files, all changes will be lost.',
|
||||
buttons: [{result: 'yes', title: 'Exit and discard unsaved changes'}, {result: '', title: 'Don\'t exit'}],
|
||||
success: function() {
|
||||
Launcher.exit();
|
||||
}
|
||||
});
|
||||
e.returnValue = false;
|
||||
return false;
|
||||
if (!this.exitAlertShown) {
|
||||
var that = this;
|
||||
that.exitAlertShown = true;
|
||||
Alerts.yesno({
|
||||
header: 'Unsaved changes!',
|
||||
body: 'You have unsaved files, all changes will be lost.',
|
||||
buttons: [{result: 'yes', title: 'Exit and discard unsaved changes'}, {result: '', title: 'Don\'t exit'}],
|
||||
success: function () {
|
||||
Launcher.exit();
|
||||
},
|
||||
cancel: function() {
|
||||
Launcher.cancelRestart(false);
|
||||
},
|
||||
complete: function () {
|
||||
that.exitAlertShown = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return Launcher.preventExit(e);
|
||||
}
|
||||
return 'You have unsaved files, all changes will be lost.';
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
'change .settings__general-theme': 'changeTheme',
|
||||
'change .settings__general-expand': 'changeExpandGroups',
|
||||
'change .settings__general-auto-update': 'changeAutoUpdate',
|
||||
'click .settings__general-update-btn': 'checkUpdate',
|
||||
'click .settings__general-restart-btn': 'restartApp',
|
||||
'click .settings__general-dev-tools-link': 'openDevTools'
|
||||
},
|
||||
|
||||
|
@ -26,6 +28,7 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
|
||||
initialize: function() {
|
||||
this.listenTo(UpdateModel.instance, 'change:status', this.render, this);
|
||||
this.listenTo(UpdateModel.instance, 'change:updateStatus', this.render, this);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -36,19 +39,13 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
devTools: Launcher && Launcher.devTools,
|
||||
canAutoUpdate: !!Launcher,
|
||||
autoUpdate: Updater.enabledAutoUpdate(),
|
||||
updateInfo: this.getUpdateInfo()
|
||||
updateInProgress: Updater.updateInProgress(),
|
||||
updateInfo: this.getUpdateInfo(),
|
||||
updateReady: UpdateModel.instance.get('updateStatus') === 'ready'
|
||||
});
|
||||
},
|
||||
|
||||
getUpdateInfo: function() {
|
||||
switch (UpdateModel.instance.get('updateStatus')) {
|
||||
case 'downloading':
|
||||
return 'Downloading update...';
|
||||
case 'downloaded':
|
||||
return 'Downloaded new version';
|
||||
case 'error':
|
||||
return 'Error downloading new version';
|
||||
}
|
||||
switch (UpdateModel.instance.get('status')) {
|
||||
case 'checking':
|
||||
return 'Checking for updates...';
|
||||
|
@ -70,6 +67,14 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
msg += 'new version ' + UpdateModel.instance.get('lastVersion') + ' available, released at ' +
|
||||
Format.dStr(UpdateModel.instance.get('lastVersionReleaseDate'));
|
||||
}
|
||||
switch (UpdateModel.instance.get('updateStatus')) {
|
||||
case 'downloading':
|
||||
return msg + '. Downloading update...';
|
||||
case 'extracting':
|
||||
return msg + '. Extracting update...';
|
||||
case 'error':
|
||||
return msg + '. There was an error downloading new version';
|
||||
}
|
||||
return msg;
|
||||
default:
|
||||
return 'Never checked for updates';
|
||||
|
@ -89,6 +94,14 @@ var SettingsGeneralView = Backbone.View.extend({
|
|||
}
|
||||
},
|
||||
|
||||
checkUpdate: function() {
|
||||
Updater.check(true);
|
||||
},
|
||||
|
||||
restartApp: function() {
|
||||
Launcher.requestRestart();
|
||||
},
|
||||
|
||||
changeExpandGroups: function(e) {
|
||||
var expand = e.target.checked;
|
||||
AppSettingsModel.instance.set('expandGroups', expand);
|
||||
|
|
|
@ -71,4 +71,14 @@
|
|||
float: right;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__general-update-buttons {
|
||||
margin-top: $base-spacing;
|
||||
}
|
||||
&__general-update-btn {
|
||||
width: 15em;
|
||||
}
|
||||
&__general-restart-btn {
|
||||
margin-left: $small-spacing;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,16 @@
|
|||
<label for="settings__general-auto-update">Automatic updates</label>
|
||||
<div><%- updateInfo %></div>
|
||||
</div>
|
||||
<div class="settings__general-update-buttons">
|
||||
<% if (updateInProgress) { %>
|
||||
<button class="settings__general-update-btn btn-silent" disabled>Checking for updates</button>
|
||||
<% } else { %>
|
||||
<button class="settings__general-update-btn btn-silent">Check for updates</button>
|
||||
<% } %>
|
||||
<% if (updateReady) { %>
|
||||
<button class="settings__general-restart-btn">Restart to update</button>
|
||||
<% } %>
|
||||
</div>
|
||||
<% } %>
|
||||
<% if (devTools) { %>
|
||||
<h2>Advanced</h2>
|
||||
|
|
|
@ -11,6 +11,7 @@ var app = require('app'),
|
|||
var mainWindow = null,
|
||||
openFile = process.argv.filter(function(arg) { return /\.kdbx$/i.test(arg); })[0],
|
||||
ready = false,
|
||||
restartPending = false,
|
||||
htmlPath = path.join(__dirname, 'index.html');
|
||||
|
||||
process.argv.forEach(function(arg) {
|
||||
|
@ -19,7 +20,9 @@ process.argv.forEach(function(arg) {
|
|||
}
|
||||
});
|
||||
|
||||
app.on('window-all-closed', function() { app.quit(); });
|
||||
app.on('window-all-closed', function() {
|
||||
app.quit();
|
||||
});
|
||||
app.on('ready', function() {
|
||||
mainWindow = new BrowserWindow({
|
||||
show: false,
|
||||
|
@ -35,13 +38,25 @@ app.on('ready', function() {
|
|||
notifyOpenFile();
|
||||
}, 50);
|
||||
});
|
||||
mainWindow.on('closed', function() { mainWindow = null; });
|
||||
mainWindow.on('closed', function() {
|
||||
mainWindow = null;
|
||||
});
|
||||
});
|
||||
app.on('open-file', function(e, path) {
|
||||
e.preventDefault();
|
||||
openFile = path;
|
||||
notifyOpenFile();
|
||||
});
|
||||
app.on('quit', function() {
|
||||
if (restartPending) {
|
||||
require('child_process').exec(process.execPath);
|
||||
}
|
||||
});
|
||||
app.quitAndRestart = function() {
|
||||
restartPending = true;
|
||||
app.quit();
|
||||
setTimeout(function() { restartPending = false; }, 1000);
|
||||
};
|
||||
|
||||
function setMenu() {
|
||||
if (process.platform === 'darwin') {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "KeeWeb",
|
||||
"version": "0.2.1",
|
||||
"description": "KeePass web app",
|
||||
"main": "launcher.js",
|
||||
"main": "main.js",
|
||||
"repository": "https://github.com/antelle/keeweb",
|
||||
"author": "Antelle",
|
||||
"license": "MIT",
|
||||
|
|
Loading…
Reference in New Issue