fix: enforce single instance of lbry app

This commit is contained in:
Sean Yesmunt 2019-03-20 15:09:58 -04:00
parent a07801f8bb
commit e5e339234a
5 changed files with 96 additions and 84 deletions

View file

@ -6,13 +6,14 @@ import url from 'url';
import https from 'https'; import https from 'https';
import { app, dialog, ipcMain, session, shell } from 'electron'; import { app, dialog, ipcMain, session, shell } from 'electron';
import { autoUpdater } from 'electron-updater'; import { autoUpdater } from 'electron-updater';
import isDev from 'electron-is-dev';
import { Lbry } from 'lbry-redux'; import { Lbry } from 'lbry-redux';
import Daemon from './Daemon'; import Daemon from './Daemon';
import isDev from 'electron-is-dev';
import createTray from './createTray'; import createTray from './createTray';
import createWindow from './createWindow'; import createWindow from './createWindow';
import pjson from '../../../package.json'; import pjson from '../../../package.json';
import startSandbox from './startSandbox'; import startSandbox from './startSandbox';
import installDevtools from './installDevtools';
autoUpdater.autoDownload = true; autoUpdater.autoDownload = true;
@ -34,11 +35,6 @@ let daemon;
const appState = {}; const appState = {};
const installExtensions = async() => {
const devtronExtension = require('devtron');
return await devtronExtension.install();
};
app.setAsDefaultProtocolClient('lbry'); app.setAsDefaultProtocolClient('lbry');
app.setName('LBRY'); app.setName('LBRY');
app.setAppUserModelId('io.lbry.LBRY'); app.setAppUserModelId('io.lbry.LBRY');
@ -53,8 +49,9 @@ if (isDev) {
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true; process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true;
} }
app.on('ready', async() => { const startDaemon = async() => {
let isDaemonRunning = false; let isDaemonRunning = false;
await Lbry.status() await Lbry.status()
.then(() => { .then(() => {
isDaemonRunning = true; isDaemonRunning = true;
@ -82,55 +79,77 @@ app.on('ready', async() => {
}); });
daemon.launch(); daemon.launch();
} }
};
startSandbox(); // When we are starting the app, ensure there are no other apps already running
const gotSingleInstanceLock = app.requestSingleInstanceLock();
if (isDev) { if (!gotSingleInstanceLock) {
// await installExtensions(); // Another instance already has a lock, abort
const { app.quit();
default: installExtension, } else {
REACT_DEVELOPER_TOOLS, app.on('second-instance', (event, argv) => {
REDUX_DEVTOOLS, // Send the url to the app to navigate first, then focus
REACT_PERF, if (rendererWindow) {
} = require('electron-devtools-installer'); if (
(process.platform === 'win32' || process.platform === 'linux') &&
String(argv[1]).startsWith('lbry')
) {
let URI = argv[1];
await installExtension(REACT_DEVELOPER_TOOLS) // Keep only command line / deep linked arguments
.then(name => console.log(`Added Extension: ${name}`)) // Windows normalizes URIs when they're passed in from other apps. On Windows, this tries to
.catch(err => console.log('An error occurred: ', err)); // restore the original URI that was typed.
// - If the URI has no path, Windows adds a trailing slash. LBRY URIs can't have a slash with no
// path, so we just strip it off.
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
// - ? also interpreted as an anchor, remove slash also.
if (process.platform === 'win32') {
URI = URI.replace(/\/$/, '')
.replace('/#', '#')
.replace('/?', '?');
}
await installExtension(REDUX_DEVTOOLS) rendererWindow.webContents.send('open-uri-requested', URI);
.then(name => console.log(`Added Extension: ${name}`)) }
.catch(err => console.log('An error occurred: ', err));
await installExtension(REACT_PERF) rendererWindow.show();
.then(name => console.log(`Added Extension: ${name}`))
.catch(err => console.log('An error occurred: ', err));
}
if (app.requestSingleInstanceLock()) {
rendererWindow = createWindow(appState);
}
rendererWindow.webContents.on('devtools-opened', () => {
rendererWindow.webContents.send('devtools-is-opened');
});
tray = createTray(rendererWindow);
// HACK: patch webrequest to fix devtools incompatibility with electron 2.x.
// See https://github.com/electron/electron/issues/13008#issuecomment-400261941
session.defaultSession.webRequest.onBeforeRequest({}, (details, callback) => {
if (details.url.indexOf('7accc8730b0f99b5e7c0702ea89d1fa7c17bfe33') !== -1) {
callback({
redirectURL: details.url.replace(
'7accc8730b0f99b5e7c0702ea89d1fa7c17bfe33',
'57c9d07b416b5a2ea23d28247300e4af36329bdc'
),
});
} else {
callback({ cancel: false });
} }
}); });
});
app.on('ready', async() => {
startDaemon();
startSandbox();
if (isDev) {
await installDevtools();
} else {
rendererWindow.webContents.on('devtools-opened', () => {
// Send a message to the renderer process so we can log a security warning
rendererWindow.webContents.send('devtools-is-opened');
});
}
rendererWindow = createWindow(appState);
tray = createTray(rendererWindow);
// HACK: patch webrequest to fix devtools incompatibility with electron 2.x.
// See https://github.com/electron/electron/issues/13008#issuecomment-400261941
session.defaultSession.webRequest.onBeforeRequest({}, (details, callback) => {
if (details.url.indexOf('7accc8730b0f99b5e7c0702ea89d1fa7c17bfe33') !== -1) {
callback({
redirectURL: details.url.replace(
'7accc8730b0f99b5e7c0702ea89d1fa7c17bfe33',
'57c9d07b416b5a2ea23d28247300e4af36329bdc'
),
});
} else {
callback({ cancel: false });
}
});
});
}
app.on('activate', () => { app.on('activate', () => {
if (rendererWindow) { if (rendererWindow) {
@ -310,33 +329,3 @@ process.on('uncaughtException', error => {
if (daemon) daemon.quit(); if (daemon) daemon.quit();
app.exit(1); app.exit(1);
}); });
// Force single instance application
app.on('second-instance', (event, argv) => {
if (rendererWindow) {
if (
(process.platform === 'win32' || process.platform === 'linux') &&
String(argv[1]).startsWith('lbry')
) {
let URI = argv[1];
// Keep only command line / deep linked arguments
// Windows normalizes URIs when they're passed in from other apps. On Windows, this tries to
// restore the original URI that was typed.
// - If the URI has no path, Windows adds a trailing slash. LBRY URIs can't have a slash with no
// path, so we just strip it off.
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
// - ? also interpreted as an anchor, remove slash also.
if (process.platform === 'win32') {
URI = URI.replace(/\/$/, '')
.replace('/#', '#')
.replace('/?', '?');
}
rendererWindow.webContents.send('open-uri-requested', URI);
}
rendererWindow.show();
}
});

View file

@ -0,0 +1,23 @@
export default async function installDevtools() {
console.log('installing');
const {
default: installExtension,
REACT_DEVELOPER_TOOLS,
REDUX_DEVTOOLS,
REACT_PERF,
} = require('electron-devtools-installer');
await installExtension(REACT_DEVELOPER_TOOLS)
.then(name => console.log(`Added Extension: ${name}`))
.catch(err => console.log('An error occurred: ', err));
await installExtension(REDUX_DEVTOOLS)
.then(name => console.log(`Added Extension: ${name}`))
.catch(err => console.log('An error occurred: ', err));
await installExtension(REACT_PERF)
.then(name => console.log(`Added Extension: ${name}`))
.catch(err => console.log('An error occurred: ', err));
console.log('all done');
}

View file

@ -101,7 +101,9 @@ class FileSelector extends React.PureComponent<Props> {
}} }}
readOnly="readonly" readOnly="readonly"
value={currentPath || __('No File Chosen')} value={currentPath || __('No File Chosen')}
inputButton={<Button button="primary" label={label} onClick={this.handleButtonClick} />} inputButton={
<Button button="primary" label={label} onClick={() => this.handleButtonClick()} />
}
/> />
</React.Fragment> </React.Fragment>
); );

View file

@ -160,8 +160,7 @@ ipcRenderer.on('window-is-focused', () => {
}); });
ipcRenderer.on('devtools-is-opened', () => { ipcRenderer.on('devtools-is-opened', () => {
const logOnDevelopment = false; doLogWarningConsoleMessage();
doLogWarningConsoleMessage(logOnDevelopment);
}); });
// @endif // @endif

View file

@ -1,7 +1,6 @@
import isDev from 'electron-is-dev'; import isDev from 'electron-is-dev';
export default function doLogWarningConsoleMessage(activeOnDev = false) { export default function doLogWarningConsoleMessage() {
if (isDev && !activeOnDev) return;
const style = { const style = {
redTitle: redTitle:
'color: red; font-size: 36px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;, font-weight: bold;', 'color: red; font-size: 36px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;, font-weight: bold;',