diff --git a/app/main.js b/app/main.js
index d0b72edae..64deeb573 100644
--- a/app/main.js
+++ b/app/main.js
@@ -1,4 +1,4 @@
-const {app, BrowserWindow, ipcMain} = require('electron');
+const {app, BrowserWindow, ipcMain, shell} = require('electron');
const path = require('path');
const jayson = require('jayson');
// tree-kill has better cross-platform handling of
@@ -27,7 +27,7 @@ function createWindow () {
};
-function lauchDaemon() {
+function launchDaemon() {
if (subpy) {
return;
}
@@ -78,7 +78,7 @@ function launchDaemonIfNotRunning() {
function (err, res) {
if (err) {
console.log('lbrynet daemon needs to be launched')
- lauchDaemon();
+ launchDaemon();
} else {
console.log('lbrynet daemon is already running')
}
@@ -115,23 +115,49 @@ app.on('activate', () => {
})
-function shutdownDaemon() {
- console.log('Shutdown triggered');
- if (subpy == null) {
- // TODO: In this case, we didn't start the process so I'm hesitant
- // to shut it down. We might want to send a stop command
- // though instead of just letting it run.
- console.log('Not killing lbrynet daemon because we did not start it')
- return
+function shutdownDaemon(evenIfNotStartedByApp = false) {
+ if (subpy) {
+ console.log('Killing lbrynet-daemon process');
+ kill(subpy.pid, undefined, (err) => {
+ console.log('Killed lbrynet-daemon process');
+ });
+ } else if (evenIfNotStartedByApp) {
+ console.log('Killing lbrynet-daemon, even though app did not start it');
+ client.request('daemon_stop', []);
+ // TODO: If the daemon errors or times out when we make this request, find
+ // the process and force quit it.
+ } else {
+ console.log('Not killing lbrynet-daemon because app did not start it')
}
+
+ // Is it safe to start the installer before the daemon finishes running?
+ // If not, we should wait until the daemon is closed before we start the install.
+}
+
+function shutdown() {
if (win) {
win.loadURL(`file://${__dirname}/dist/quit.html`);
}
quitting = true;
- console.log('Killing lbrynet-daemon process');
- kill(subpy.pid, undefined, (err) => {
- console.log('Killed lbrynet-daemon process');
- });
+ shutdownDaemon();
}
-ipcMain.on('shutdown', shutdownDaemon);
+function upgrade(event, installerPath) {
+ app.on('quit', () => {
+ shell.openItem(installerPath);
+ });
+ if (win) {
+ win.loadURL(`file://${__dirname}/dist/upgrade.html`);
+ }
+ quitting = true;
+ shutdownDaemon(true);
+ // wait for daemon to shut down before upgrading
+ // what to do if no shutdown in a long time?
+ console.log('Update downloaded to ', installerPath);
+ console.log('The app will close, and you will be prompted to install the latest version of LBRY.');
+ console.log('After the install is complete, please reopen the app.');
+}
+
+ipcMain.on('upgrade', upgrade);
+
+ipcMain.on('shutdown', shutdown);
\ No newline at end of file
diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md
index f875ffe07..b8c82b321 100644
--- a/ui/CHANGELOG.md
+++ b/ui/CHANGELOG.md
@@ -13,7 +13,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
* Wherever possible, use outpoints for unique IDs instead of names or SD hashes
### Changed
- *
+ * Update process now easier and more reliable
*
*
diff --git a/ui/dist/upgrade.html b/ui/dist/upgrade.html
new file mode 100644
index 000000000..89345ccc4
--- /dev/null
+++ b/ui/dist/upgrade.html
@@ -0,0 +1,37 @@
+
+
+
+
+ LBRY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Starting LBRY Upgrade
+
+
+
+
+
+
diff --git a/ui/js/app.js b/ui/js/app.js
index 466fde6ad..79ff80873 100644
--- a/ui/js/app.js
+++ b/ui/js/app.js
@@ -24,6 +24,9 @@ import {Link} from './component/link.js';
const {remote, ipcRenderer, shell} = require('electron');
const {download} = remote.require('electron-dl');
+const os = require('os');
+const path = require('path');
+const app = require('electron').remote.app;
var App = React.createClass({
@@ -36,6 +39,19 @@ var App = React.createClass({
data: 'Error data',
},
+ _upgradeDownloadItem: null,
+ _version: null,
+
+ // Temporary workaround since electron-dl throws errors when you try to get the filename
+ getUpgradeFilename: function() {
+ if (os.platform() == 'darwin') {
+ return `LBRY-${this._version}.dmg`;
+ } else if (os.platform() == 'linux') {
+ return `LBRY-${this._version}.deb`;
+ } else {
+ return `LBRY-${this._version}_amd64.deb`;
+ }
+ },
getInitialState: function() {
// For now, routes are in format ?page or ?page=args
var match, param, val, viewingPage,
@@ -53,6 +69,7 @@ var App = React.createClass({
updateUrl: null,
isOldOSX: null,
downloadProgress: null,
+ downloadComplete: false,
};
},
componentWillMount: function() {
@@ -79,6 +96,8 @@ var App = React.createClass({
}
lbry.getVersionInfo((versionInfo) => {
+ this._version = versionInfo.lbrynet_version; // temp for building upgrade filename
+
var isOldOSX = false;
if (versionInfo.os_system == 'Darwin') {
var updateUrl = 'https://lbry.io/get/lbry.dmg';
@@ -91,10 +110,7 @@ var App = React.createClass({
} else if (versionInfo.os_system == 'Linux') {
var updateUrl = 'https://lbry.io/get/lbry.deb';
} else if (versionInfo.os_system == 'Windows') {
- // A little weird, but for electron, the installer is
- // actually an exe. Maybe a better url would
- // be something like /get/windows ?
- var updateUrl = 'https://lbry.io/get/lbry.msi';
+ var updateUrl = 'https://lbry.io/get/lbry.exe';
} else {
var updateUrl = 'https://lbry.io/get';
}
@@ -123,17 +139,51 @@ var App = React.createClass({
handleUpgradeClicked: function() {
// TODO: create a callback for onProgress and have the UI
// show download progress
- // TODO: remove the saveAs popup. Thats just me being lazy and having
- // some indication that the download is happening
// TODO: calling lbry.stop() ends up displaying the "daemon
// unexpectedly stopped" page. Have a better way of shutting down
+ let dir = app.getPath('temp');
let options = {
onProgress: (p) => this.setState({downloadProgress: Math.round(p * 100)}),
- }
+ directory: dir,
+ };
download(remote.getCurrentWindow(), this.state.updateUrl, options)
- .then(dl => ipcRenderer.send('shutdown'));
+ .then(downloadItem => {
+ /**
+ * TODO: get the download path directly from the download object. It should just be
+ * downloadItem.getSavePath(), but the copy on the main process is being garbage collected
+ * too soon.
+ */
+
+ this._upgradeDownloadItem = downloadItem;
+ this._upgradeDownloadPath = path.join(dir, this.getUpgradeFilename());
+ this.setState({
+ downloadComplete: true
+ });
+ });
this.setState({modal: 'downloading'});
},
+ handleStartUpgradeClicked: function() {
+ ipcRenderer.send('upgrade', this._upgradeDownloadPath);
+ },
+ cancelUpgrade: function() {
+ if (this._upgradeDownloadItem) {
+ /*
+ * Right now the remote reference to the download item gets garbage collected as soon as the
+ * the download is over (maybe even earlier), so trying to cancel a finished download may
+ * throw an error.
+ */
+ try {
+ this._upgradeDownloadItem.cancel();
+ } catch (err) {
+ // Do nothing
+ }
+ }
+ this.setState({
+ downloadProgress: null,
+ downloadComplete: false,
+ modal: null,
+ });
+ },
handleSkipClicked: function() {
sessionStorage.setItem('upgradeSkipped', true);
this.setState({
@@ -246,8 +296,22 @@ var App = React.createClass({
- Downloading Update: {this.state.downloadProgress}% Complete
+ Downloading Update{this.state.downloadProgress ? `: ${this.state.downloadProgress}%` : null}
+ {this.state.downloadComplete ? (
+
+
+
Click "Begin Upgrade" to start the upgrade process.
+
The app will close, and you will be prompted to install the latest version of LBRY.
+
After the install is complete, please reopen the app.