2017-12-21 18:32:51 +01:00
|
|
|
|
/* eslint-disable no-console */
|
2017-11-17 21:35:37 +01:00
|
|
|
|
// Module imports
|
2018-01-18 03:13:08 +01:00
|
|
|
|
import keytar from 'keytar-prebuild';
|
2018-01-08 04:46:22 +01:00
|
|
|
|
import SemVer from 'semver';
|
2018-01-18 03:13:08 +01:00
|
|
|
|
import url from 'url';
|
2018-01-08 04:46:22 +01:00
|
|
|
|
import https from 'https';
|
2018-01-18 03:13:08 +01:00
|
|
|
|
import { shell, app, ipcMain, dialog } from 'electron';
|
2017-11-18 06:08:44 +01:00
|
|
|
|
import { autoUpdater } from 'electron-updater';
|
2018-01-18 03:13:08 +01:00
|
|
|
|
import Daemon from './Daemon';
|
|
|
|
|
import Tray from './Tray';
|
|
|
|
|
import createWindow from './createWindow';
|
2017-12-13 22:36:30 +01:00
|
|
|
|
|
2017-12-22 07:42:04 +01:00
|
|
|
|
autoUpdater.autoDownload = true;
|
|
|
|
|
|
2018-01-08 21:43:25 +01:00
|
|
|
|
// This is set to true if an auto update has been downloaded through the Electron
|
|
|
|
|
// auto-update system and is ready to install. If the user declined an update earlier,
|
|
|
|
|
// it will still install on shutdown.
|
|
|
|
|
let autoUpdateDownloaded = false;
|
|
|
|
|
|
|
|
|
|
// Keeps track of whether the user has accepted an auto-update through the interface.
|
|
|
|
|
let autoUpdateAccepted = false;
|
2018-01-02 12:51:37 +01:00
|
|
|
|
|
2018-01-24 01:46:49 +01:00
|
|
|
|
// This is used to keep track of whether we are showing the special dialog
|
2018-01-02 12:51:37 +01:00
|
|
|
|
// that we show on Windows after you decline an upgrade and close the app later.
|
2018-01-05 07:29:31 +01:00
|
|
|
|
let showingAutoUpdateCloseAlert = false;
|
2018-01-02 12:51:37 +01:00
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
// Keep a global reference, if you don't, they will be closed automatically when the JavaScript
|
|
|
|
|
// object is garbage collected.
|
2017-12-21 18:32:51 +01:00
|
|
|
|
let rendererWindow;
|
2018-01-18 03:13:08 +01:00
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
|
let tray;
|
|
|
|
|
let daemon;
|
|
|
|
|
|
|
|
|
|
let isQuitting;
|
|
|
|
|
|
|
|
|
|
const updateRendererWindow = window => {
|
|
|
|
|
rendererWindow = window;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const installExtensions = async () => {
|
|
|
|
|
// eslint-disable-next-line import/no-extraneous-dependencies,global-require
|
|
|
|
|
const installer = require('electron-devtools-installer');
|
|
|
|
|
// eslint-disable-next-line import/no-extraneous-dependencies,global-require
|
|
|
|
|
const devtronExtension = require('devtron');
|
|
|
|
|
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
|
|
|
|
const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
|
|
|
|
|
|
|
|
|
|
return Promise.all(
|
|
|
|
|
extensions.map(
|
|
|
|
|
name => installer.default(installer[name], forceDownload),
|
|
|
|
|
devtronExtension.install()
|
|
|
|
|
)
|
|
|
|
|
).catch(console.log);
|
|
|
|
|
};
|
2018-01-02 12:51:37 +01:00
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
app.setAsDefaultProtocolClient('lbry');
|
|
|
|
|
app.setName('LBRY');
|
|
|
|
|
|
|
|
|
|
app.on('ready', async () => {
|
|
|
|
|
daemon = new Daemon();
|
|
|
|
|
daemon.on('exit', () => {
|
|
|
|
|
daemon = null;
|
|
|
|
|
if (!isQuitting) {
|
|
|
|
|
dialog.showErrorBox(
|
|
|
|
|
'Daemon has Exited',
|
|
|
|
|
'The daemon may have encountered an unexpected error, or another daemon instance is already running.'
|
|
|
|
|
);
|
|
|
|
|
app.quit();
|
2017-03-24 00:07:08 +01:00
|
|
|
|
}
|
2017-12-13 22:36:30 +01:00
|
|
|
|
});
|
2018-01-18 03:13:08 +01:00
|
|
|
|
daemon.launch();
|
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
|
|
|
await installExtensions();
|
2017-05-11 09:30:23 +02:00
|
|
|
|
}
|
2018-01-18 03:13:08 +01:00
|
|
|
|
rendererWindow = createWindow();
|
|
|
|
|
tray = new Tray(rendererWindow, updateRendererWindow);
|
|
|
|
|
tray.create();
|
2017-10-13 00:04:31 +02:00
|
|
|
|
});
|
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
app.on('activate', () => {
|
|
|
|
|
// On macOS it's common to re-create a window in the app when the
|
|
|
|
|
// dock icon is clicked and there are no other windows open.
|
|
|
|
|
if (!rendererWindow) rendererWindow = createWindow();
|
2017-10-13 00:04:31 +02:00
|
|
|
|
});
|
2017-12-21 18:32:51 +01:00
|
|
|
|
|
2018-01-29 13:04:41 +01:00
|
|
|
|
app.on('will-quit', event => {
|
|
|
|
|
if (
|
|
|
|
|
process.platform === 'win32' &&
|
|
|
|
|
autoUpdateDownloaded &&
|
|
|
|
|
!autoUpdateAccepted &&
|
|
|
|
|
!showingAutoUpdateCloseAlert
|
|
|
|
|
) {
|
2018-01-23 08:44:15 +01:00
|
|
|
|
// We're on Win and have an update downloaded, but the user declined it (or closed
|
|
|
|
|
// the app without accepting it). Now the user is closing the app, so the new update
|
|
|
|
|
// will install. On Mac this is silent, but on Windows they get a confusing permission
|
|
|
|
|
// escalation dialog, so we show Windows users a warning dialog first.
|
|
|
|
|
|
|
|
|
|
showingAutoUpdateCloseAlert = true;
|
2018-01-29 13:04:41 +01:00
|
|
|
|
dialog.showMessageBox(
|
|
|
|
|
{
|
|
|
|
|
type: 'info',
|
|
|
|
|
title: 'LBRY Will Upgrade',
|
|
|
|
|
message:
|
|
|
|
|
'LBRY has a pending upgrade. Please select "Yes" to install it on the prompt shown after this one.',
|
|
|
|
|
},
|
|
|
|
|
() => {
|
|
|
|
|
app.quit();
|
|
|
|
|
}
|
|
|
|
|
);
|
2017-12-04 21:46:51 +01:00
|
|
|
|
|
2018-01-24 01:46:49 +01:00
|
|
|
|
event.preventDefault();
|
2018-01-23 08:44:15 +01:00
|
|
|
|
return;
|
2017-12-04 21:46:51 +01:00
|
|
|
|
}
|
2017-01-16 20:06:53 +01:00
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
isQuitting = true;
|
|
|
|
|
if (daemon) daemon.quit();
|
2017-12-13 22:36:30 +01:00
|
|
|
|
});
|
2017-02-23 19:46:25 +01:00
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
// https://electronjs.org/docs/api/app#event-will-finish-launching
|
|
|
|
|
app.on('will-finish-launching', () => {
|
|
|
|
|
// Protocol handler for macOS
|
|
|
|
|
app.on('open-url', (event, URL) => {
|
2017-03-24 00:07:08 +01:00
|
|
|
|
event.preventDefault();
|
2018-01-18 03:13:08 +01:00
|
|
|
|
if (rendererWindow && !rendererWindow.isDestroyed()) {
|
|
|
|
|
rendererWindow.webContents.send('open-uri-requested', URL);
|
|
|
|
|
rendererWindow.show();
|
|
|
|
|
rendererWindow.focus();
|
2017-12-13 22:36:30 +01:00
|
|
|
|
} else {
|
2018-01-18 03:13:08 +01:00
|
|
|
|
rendererWindow = createWindow(URL);
|
2018-01-08 21:43:25 +01:00
|
|
|
|
}
|
2017-12-13 22:36:30 +01:00
|
|
|
|
});
|
2017-03-24 00:07:08 +01:00
|
|
|
|
});
|
2017-01-18 17:32:01 +01:00
|
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
|
app.on('window-all-closed', () => {
|
2018-01-18 03:13:08 +01:00
|
|
|
|
// Subscribe to event so the app doesn't quit when closing the window.
|
2017-03-24 00:07:08 +01:00
|
|
|
|
});
|
2017-02-20 19:59:03 +01:00
|
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
|
ipcMain.on('upgrade', (event, installerPath) => {
|
|
|
|
|
app.on('quit', () => {
|
|
|
|
|
console.log('Launching upgrade installer at', installerPath);
|
2017-03-24 00:07:08 +01:00
|
|
|
|
// This gets triggered called after *all* other quit-related events, so
|
|
|
|
|
// we'll only get here if we're fully prepared and quitting for real.
|
2018-01-18 03:13:08 +01:00
|
|
|
|
shell.openItem(installerPath);
|
2017-02-20 19:59:03 +01:00
|
|
|
|
});
|
2017-03-17 23:05:25 +01:00
|
|
|
|
// what to do if no shutdown in a long time?
|
2017-12-21 18:32:51 +01:00
|
|
|
|
console.log('Update downloaded to', installerPath);
|
2017-12-13 22:36:30 +01:00
|
|
|
|
console.log(
|
2017-12-21 18:32:51 +01:00
|
|
|
|
'The app will close, and you will be prompted to install the latest version of LBRY.'
|
2017-12-13 22:36:30 +01:00
|
|
|
|
);
|
2017-12-21 18:32:51 +01:00
|
|
|
|
console.log('After the install is complete, please reopen the app.');
|
2018-01-18 03:13:08 +01:00
|
|
|
|
app.quit();
|
2017-12-04 21:46:51 +01:00
|
|
|
|
});
|
2017-02-20 19:59:03 +01:00
|
|
|
|
|
2018-01-23 08:44:15 +01:00
|
|
|
|
autoUpdater.on('update-downloaded', () => {
|
|
|
|
|
autoUpdateDownloaded = true;
|
2018-01-29 13:04:41 +01:00
|
|
|
|
});
|
2018-01-23 08:44:15 +01:00
|
|
|
|
|
|
|
|
|
ipcMain.on('autoUpdateAccepted', () => {
|
|
|
|
|
autoUpdateAccepted = true;
|
|
|
|
|
autoUpdater.quitAndInstall();
|
2017-12-04 21:46:51 +01:00
|
|
|
|
});
|
2017-02-20 19:59:03 +01:00
|
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
|
ipcMain.on('version-info-requested', () => {
|
2017-12-04 21:46:51 +01:00
|
|
|
|
function formatRc(ver) {
|
2018-01-18 03:13:08 +01:00
|
|
|
|
// Adds dash if needed to make RC suffix SemVer friendly
|
2017-12-21 18:32:51 +01:00
|
|
|
|
return ver.replace(/([^-])rc/, '$1-rc');
|
2017-12-04 21:46:51 +01:00
|
|
|
|
}
|
2017-09-14 09:36:41 +02:00
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
const localVersion = app.getVersion();
|
|
|
|
|
const latestReleaseAPIURL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest';
|
2017-12-04 21:46:51 +01:00
|
|
|
|
const opts = {
|
|
|
|
|
headers: {
|
2017-12-21 18:32:51 +01:00
|
|
|
|
'User-Agent': `LBRY/${localVersion}`,
|
2017-12-13 22:36:30 +01:00
|
|
|
|
},
|
2017-12-04 21:46:51 +01:00
|
|
|
|
};
|
2018-01-18 03:13:08 +01:00
|
|
|
|
let result = '';
|
2017-05-05 11:15:58 +02:00
|
|
|
|
|
2018-01-08 04:46:22 +01:00
|
|
|
|
const req = https.get(Object.assign(opts, url.parse(latestReleaseAPIURL)), res => {
|
2017-12-21 18:32:51 +01:00
|
|
|
|
res.on('data', data => {
|
|
|
|
|
result += data;
|
|
|
|
|
});
|
|
|
|
|
res.on('end', () => {
|
|
|
|
|
const tagName = JSON.parse(result).tag_name;
|
|
|
|
|
const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
|
|
|
|
if (!remoteVersion) {
|
|
|
|
|
if (rendererWindow) {
|
|
|
|
|
rendererWindow.webContents.send('version-info-received', null);
|
2017-12-04 21:46:51 +01:00
|
|
|
|
}
|
2017-12-21 18:32:51 +01:00
|
|
|
|
} else {
|
2018-01-08 04:46:22 +01:00
|
|
|
|
const upgradeAvailable = SemVer.gt(formatRc(remoteVersion), formatRc(localVersion));
|
2017-12-21 18:32:51 +01:00
|
|
|
|
if (rendererWindow) {
|
|
|
|
|
rendererWindow.webContents.send('version-info-received', {
|
|
|
|
|
remoteVersion,
|
|
|
|
|
localVersion,
|
|
|
|
|
upgradeAvailable,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
2017-05-10 10:44:06 +02:00
|
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
|
req.on('error', err => {
|
|
|
|
|
console.log('Failed to get current version from GitHub. Error:', err);
|
|
|
|
|
if (rendererWindow) {
|
|
|
|
|
rendererWindow.webContents.send('version-info-received', null);
|
2017-12-04 21:46:51 +01:00
|
|
|
|
}
|
2017-05-05 11:15:58 +02:00
|
|
|
|
});
|
2017-12-04 21:46:51 +01:00
|
|
|
|
});
|
2017-06-26 16:47:49 +02:00
|
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
|
ipcMain.on('get-auth-token', event => {
|
2018-01-08 04:46:22 +01:00
|
|
|
|
keytar.getPassword('LBRY', 'auth_token').then(token => {
|
2017-12-21 18:32:51 +01:00
|
|
|
|
event.sender.send('auth-token-response', token ? token.toString().trim() : null);
|
2017-06-26 16:47:49 +02:00
|
|
|
|
});
|
|
|
|
|
});
|
2018-01-08 21:43:25 +01:00
|
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
|
ipcMain.on('set-auth-token', (event, token) => {
|
2018-01-08 04:46:22 +01:00
|
|
|
|
keytar.setPassword('LBRY', 'auth_token', token ? token.toString().trim() : null);
|
2018-01-08 21:43:25 +01:00
|
|
|
|
});
|
|
|
|
|
|
2018-01-08 06:16:31 +01:00
|
|
|
|
process.on('uncaughtException', error => {
|
2018-01-18 03:13:08 +01:00
|
|
|
|
dialog.showErrorBox('Error Encountered', `Caught error: ${error}`);
|
|
|
|
|
isQuitting = true;
|
|
|
|
|
if (daemon) daemon.quit();
|
|
|
|
|
app.exit(1);
|
2018-01-05 07:29:31 +01:00
|
|
|
|
});
|
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
// Force single instance application
|
|
|
|
|
const isSecondInstance = app.makeSingleInstance(argv => {
|
|
|
|
|
// Protocol handler for win32
|
|
|
|
|
// argv: An array of the second instance’s (command line / deep linked) arguments
|
2017-12-10 09:01:24 +01:00
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
let URI;
|
|
|
|
|
if (process.platform === 'win32' && String(argv[1]).startsWith('lbry')) {
|
|
|
|
|
// Keep only command line / deep linked arguments
|
|
|
|
|
URI = argv[1].replace(/\/$/, '').replace('/#', '#');
|
|
|
|
|
}
|
2017-06-26 16:47:49 +02:00
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
if (rendererWindow && !rendererWindow.isDestroyed()) {
|
|
|
|
|
rendererWindow.webContents.send('open-uri-requested', URI);
|
|
|
|
|
|
|
|
|
|
rendererWindow.show();
|
|
|
|
|
rendererWindow.focus();
|
|
|
|
|
} else {
|
|
|
|
|
rendererWindow = createWindow(URI);
|
|
|
|
|
}
|
2017-11-29 01:29:59 +01:00
|
|
|
|
});
|
2018-01-05 23:25:33 +01:00
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
|
if (isSecondInstance) {
|
|
|
|
|
app.exit();
|
2018-01-29 13:04:41 +01:00
|
|
|
|
}
|