index.ts 4.33 KiB
Newer Older
Amaury Martiny's avatar
Amaury Martiny committed
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
Amaury Martiny's avatar
Amaury Martiny committed
// SPDX-License-Identifier: BSD-3-Clause
import parityElectron, {
  getParityPath,
  fetchParity,
Axel Chalon's avatar
Axel Chalon committed
  isParityRunning,
  runParity,
  killParity
} from '@parity/electron';
import electron from 'electron';
import getRemainingArgs from 'commander-remaining-args';
import path from 'path';
import url from 'url';
Amaury Martiny's avatar
Amaury Martiny committed
import addMenu from './menu';
import cli from './cli';
import handleError from './utils/handleError';
import messages from './messages';
import { parity } from '../../package.json';
Amaury Martiny's avatar
Amaury Martiny committed
import Pino from './utils/pino';
import { productName } from '../../electron-builder.json';
Amaury Martiny's avatar
Amaury Martiny committed
import staticPath from './utils/staticPath';
Amaury Martiny's avatar
Amaury Martiny committed
const { app, BrowserWindow, ipcMain, session } = electron;
let mainWindow;
Amaury Martiny's avatar
Amaury Martiny committed
const pino = Pino();
// Disable gpu acceleration on linux
// https://github.com/parity-js/fether/issues/85
if (!['darwin', 'win32'].includes(process.platform)) {
  app.disableHardwareAcceleration();
}

Amaury Martiny's avatar
Amaury Martiny committed
function createWindow () {
Amaury Martiny's avatar
Amaury Martiny committed
  pino.info(`Starting ${productName}...`);
Amaury Martiny's avatar
Amaury Martiny committed
  mainWindow = new BrowserWindow({
    height: 640,
    resizable: false,
    width: 360
  });
  // Set options for @parity/electron
  parityElectron({
    logger: namespace => log => Pino({ name: namespace }).info(log)
  // Look if Parity is installed
    .catch(() =>
      // Install parity if not present
      fetchParity(mainWindow, {
        onProgress: progress =>
          // Notify the renderers on download progress
          mainWindow.webContents.send('parity-download-progress', progress),
        parityChannel: parity.channel
      })
Axel Chalon's avatar
Axel Chalon committed
    .then(async () => {
      // Run parity when installed
Axel Chalon's avatar
Axel Chalon committed

      // Don't run parity if the user ran fether with --no-run-parity
      if (!cli.runParity) {
        return;
      }

Axel Chalon's avatar
Axel Chalon committed
      if (
        await isParityRunning({
          wsInterface: cli.wsInterface,
          wsPort: cli.wsPort
        })
      ) {
Axel Chalon's avatar
Axel Chalon committed
        return;
      }

      return runParity({
        flags: [
          ...getRemainingArgs(cli),
          '--light',
Axel Chalon's avatar
Axel Chalon committed
          '--chain',
          cli.chain,
          '--ws-interface',
          cli.wsInterface,
          '--ws-port',
          cli.wsPort
Axel Chalon's avatar
Axel Chalon committed
        ],
Axel Chalon's avatar
Axel Chalon committed
        onParityError: err => handleError(err, 'An error occured with Parity.')
Axel Chalon's avatar
Axel Chalon committed
      });
    })
    .then(() => {
      // Notify the renderers
      mainWindow.webContents.send('parity-running', true);
      global.isParityRunning = true; // Send this variable to renderes via IPC
    })
    .catch(handleError);
  // Globals for fether-react parityStore
  global.wsInterface = cli.wsInterface;
  global.wsPort = cli.wsPort;

Amaury Martiny's avatar
Amaury Martiny committed
  // Opens file:///path/to/build/index.html in prod mode, or whatever is
  // passed to ELECTRON_START_URL
  mainWindow.loadURL(
    process.env.ELECTRON_START_URL ||
Axel Chalon's avatar
Axel Chalon committed
      url.format({
        pathname: path.join(staticPath, 'build', 'index.html'),
        protocol: 'file:',
        slashes: true
      })
Amaury Martiny's avatar
Amaury Martiny committed
  );

Amaury Martiny's avatar
Amaury Martiny committed
  // Listen to messages from renderer process
Amaury Martiny's avatar
Amaury Martiny committed
  ipcMain.on('asynchronous-message', (...args) =>
    messages(mainWindow, ...args)
  );
Amaury Martiny's avatar
Amaury Martiny committed
  // Add application menu
  addMenu(mainWindow);

Amaury Martiny's avatar
Amaury Martiny committed
  // WS calls have Origin `file://` by default, which is not trusted.
  // We override Origin header on all WS connections with an authorized one.
  session.defaultSession.webRequest.onBeforeSendHeaders(
    {
      urls: ['ws://*/*', 'wss://*/*']
    },
    (details, callback) => {
Amaury Martiny's avatar
Amaury Martiny committed
      if (!mainWindow) {
        // There might be a split second where the user closes the app, so
Amaury Martiny's avatar
Amaury Martiny committed
        // mainWindow is null, but there is still a network request done.
Amaury Martiny's avatar
Amaury Martiny committed
      details.requestHeaders.Origin = `parity://${mainWindow.id}.ui.parity`;
Amaury Martiny's avatar
Amaury Martiny committed
      callback({ requestHeaders: details.requestHeaders }); // eslint-disable-line
  // Open external links in browser
Amaury Martiny's avatar
Amaury Martiny committed
  mainWindow.webContents.on('new-window', function (event, url) {
    event.preventDefault();
    electron.shell.openExternal(url);
  });
Amaury Martiny's avatar
Amaury Martiny committed

  mainWindow.on('closed', () => {
    mainWindow = null;
  });
Amaury Martiny's avatar
Amaury Martiny committed
app.on('ready', createWindow);
Amaury Martiny's avatar
Amaury Martiny committed
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    killParity();
    app.quit();
  }
Amaury Martiny's avatar
Amaury Martiny committed
});

// Make sure parity stops when UI stops
Amaury Martiny's avatar
Amaury Martiny committed
app.on('before-quit', killParity);
app.on('will-quit', killParity);
app.on('quit', killParity);
Amaury Martiny's avatar
Amaury Martiny committed
app.on('activate', () => {
  if (mainWindow === null) {
    createWindow();
  }
});