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 { app, dialog, ipcMain, session, shell } from 'electron';
import { autoUpdater } from 'electron-updater';
import isDev from 'electron-is-dev';
import { Lbry } from 'lbry-redux';
import Daemon from './Daemon';
import isDev from 'electron-is-dev';
import createTray from './createTray';
import createWindow from './createWindow';
import pjson from '../../../package.json';
import startSandbox from './startSandbox';
import installDevtools from './installDevtools';
autoUpdater.autoDownload = true;
@ -34,11 +35,6 @@ let daemon;
const appState = {};
const installExtensions = async() => {
const devtronExtension = require('devtron');
return await devtronExtension.install();
};
app.setAsDefaultProtocolClient('lbry');
app.setName('LBRY');
app.setAppUserModelId('io.lbry.LBRY');
@ -53,8 +49,9 @@ if (isDev) {
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true;
}
app.on('ready', async() => {
const startDaemon = async() => {
let isDaemonRunning = false;
await Lbry.status()
.then(() => {
isDaemonRunning = true;
@ -82,40 +79,61 @@ app.on('ready', async() => {
});
daemon.launch();
}
};
// When we are starting the app, ensure there are no other apps already running
const gotSingleInstanceLock = app.requestSingleInstanceLock();
if (!gotSingleInstanceLock) {
// Another instance already has a lock, abort
app.quit();
} else {
app.on('second-instance', (event, argv) => {
// Send the url to the app to navigate first, then focus
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();
}
});
app.on('ready', async() => {
startDaemon();
startSandbox();
if (isDev) {
// await installExtensions();
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));
}
if (app.requestSingleInstanceLock()) {
rendererWindow = createWindow(appState);
}
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) => {
@ -131,6 +149,7 @@ app.on('ready', async() => {
}
});
});
}
app.on('activate', () => {
if (rendererWindow) {
@ -310,33 +329,3 @@ process.on('uncaughtException', error => {
if (daemon) daemon.quit();
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"
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>
);

View file

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

View file

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