summaryrefslogtreecommitdiffhomepage
path: root/app
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@codeispoetry.ru>2017-06-19 19:27:56 +0300
committerAndrej Mihajlov <and@codeispoetry.ru>2017-06-21 14:04:44 +0300
commite66612386ca9941f982b2d16cf4e8fc8e1d0fa14 (patch)
tree01c243fabcc9607a0bad6b7e8171837a5e5d7b2b /app
parent9fd74d9e39df895d8bc2c8856c9a6ad807012560 (diff)
downloadmullvadvpn-e66612386ca9941f982b2d16cf4e8fc8e1d0fa14.tar.xz
mullvadvpn-e66612386ca9941f982b2d16cf4e8fc8e1d0fa14.zip
Refactor main process
Diffstat (limited to 'app')
-rw-r--r--app/main.js399
1 files changed, 206 insertions, 193 deletions
diff --git a/app/main.js b/app/main.js
index 0360d43f05..62d98010ee 100644
--- a/app/main.js
+++ b/app/main.js
@@ -1,3 +1,4 @@
+// @flow
import path from 'path';
import fs from 'fs';
import sudo from 'sudo-prompt';
@@ -5,241 +6,253 @@ import log from 'electron-log';
import { app, BrowserWindow, ipcMain, Tray, Menu, nativeImage } from 'electron';
import TrayIconManager from './lib/tray-icon-manager';
+import type { TrayIconType } from './lib/tray-icon-manager';
+
const isDevelopment = (process.env.NODE_ENV === 'development');
const isMacOS = (process.platform === 'darwin');
-let window = null;
-let tray = null;
+const appDelegate = {
+ _window: (null: ?BrowserWindow),
+ _tray: (null: ?Tray),
-// Override appData path to avoid collisions with old client
-// New userData path, i.e on macOS: ~/Library/Application Support/mullvad.vpn
-app.setPath('userData', path.join(app.getPath('appData'), 'mullvad.vpn'));
+ setup: () => {
+ // Override appData path to avoid collisions with old client
+ // New userData path, i.e on macOS: ~/Library/Application Support/mullvad.vpn
+ app.setPath('userData', path.join(app.getPath('appData'), 'mullvad.vpn'));
-ipcMain.on('on-browser-window-ready', () => {
- sendBackendInfo();
-});
+ if (isDevelopment) {
+ log.transports.console.level = 'debug';
-const configureLogger = () => {
+ // Disable log file in development
+ log.transports.file.level = false;
+ } else {
+ log.transports.console.level = 'info';
+ log.transports.file.level = 'info';
+ }
- if (isDevelopment) {
- log.transports.console.level = 'debug';
+ if (isDevelopment) {
+ appDelegate._startBackend();
+ }
- // Disable log file in development
- log.transports.file.level = false;
- } else {
- log.transports.console.level = 'info';
- log.transports.file.level = 'info';
- }
-};
-configureLogger();
+ app.on('window-all-closed', () => appDelegate.onAllWindowsClosed());
+ app.on('ready', () => appDelegate.onReady());
+ },
-const installDevTools = async () => {
- const installer = require('electron-devtools-installer');
- const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
- const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
- for(const name of extensions) {
- try {
- await installer.default(installer[name], forceDownload);
- } catch (e) {
- log.info(`Error installing ${name} extension: ${e.message}`);
- }
- }
-};
+ onReady: async () => {
+ const window = appDelegate._window = appDelegate._createWindow();
-const createWindow = () => {
- const contentHeight = 568;
- let options = {
- width: 320,
- height: contentHeight,
- resizable: false,
- maximizable: false,
- fullscreenable: false,
- show: true,
- webPreferences: {
- // prevents renderer process code from not running when window is hidden
- backgroundThrottling: false,
- // Enable experimental features
- blinkFeatures: ['CSSBackdropFilter'].join(',')
- }
- };
+ ipcMain.on('on-browser-window-ready', () => appDelegate._sendBackendInfo(window));
- // setup window flags to mimic popover on macOS
- if(isMacOS) {
- options = Object.assign({}, options, {
- height: contentHeight + 12, // 12 is the size of transparent area around arrow
- frame: false,
- transparent: true,
- show: false
- });
- }
+ window.loadURL('file://' + path.join(__dirname, 'index.html'));
- window = new BrowserWindow(options);
- window.loadURL('file://' + path.join(__dirname, 'index.html'));
-};
+ // create tray icon on macOS
+ if(isMacOS) {
+ appDelegate._tray = appDelegate._createTray(window);
+ }
-const createAppMenu = () => {
- const template = [
- {
- label: 'Mullvad',
- submenu: [
- { role: 'about' },
- { type: 'separator' },
- { role: 'quit' }
- ]
- },
- {
- label: 'Edit',
- submenu: [
- { role: 'cut' },
- { role: 'copy' },
- { role: 'paste' },
- { type: 'separator' },
- { role: 'selectall' }
- ]
+ appDelegate._setAppMenu();
+ appDelegate._addContextMenu(window);
+
+ if(isDevelopment) {
+ await appDelegate._installDevTools();
+ window.openDevTools({ mode: 'detach' });
}
- ];
+ },
- Menu.setApplicationMenu(Menu.buildFromTemplate(template));
-};
+ onAllWindowsClosed: () => {
+ app.quit();
+ },
+
+ _startBackend: () => {
+ const pathToBackend = path.resolve(process.env.MULLVAD_BACKEND || '../talpid_core/target/debug/talpid_daemon');
+ log.info('Starting the mullvad backend at', pathToBackend);
-const createContextMenu = () => {
- let menuTemplate = [
- { role: 'cut' },
- { role: 'copy' },
- { role: 'paste' },
- { type: 'separator' },
- { role: 'selectall' }
- ];
+ const options = {
+ name: 'mullvad backend',
+ };
- // add inspect element on right click menu
- window.webContents.on('context-menu', (_e, props) => {
- let inspectTemplate = [{
- label: 'Inspect element',
- click() {
- window.openDevTools({ mode: 'detach' });
- window.inspectElement(props.x, props.y);
+ sudo.exec(pathToBackend, options, (err) => {
+ if (err && err.signal !== 'SIGINT') {
+ log.info('Backend exited with error', err);
+ } else {
+ log.info('Backend exited');
}
- }];
+ });
+ },
- if(props.isEditable) {
- let inputMenu = menuTemplate;
+ _sendBackendInfo: (window: BrowserWindow) => {
+ const file = './.mullvad_rpc_address';
+ log.info('reading the ipc connection info from', file);
- // mixin 'inspect element' into standard menu when in development mode
- if(isDevelopment) {
- inputMenu = menuTemplate.concat([{type: 'separator'}], inspectTemplate);
+ fs.readFile(file, 'utf8', function (err,data) {
+ if (err) {
+ return log.info('Could not find backend connection info', err);
}
- Menu.buildFromTemplate(inputMenu).popup(window);
- } else if(isDevelopment) {
- // display inspect element for all non-editable
- // elements when in development mode
- Menu.buildFromTemplate(inspectTemplate).popup(window);
+ log.info('Read IPC connection info', data);
+ window.webContents.send('backend-info', {
+ addr: data,
+ });
+ });
+ },
+
+ _installDevTools: async () => {
+ const installer = require('electron-devtools-installer');
+ const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
+ const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
+ for(const name of extensions) {
+ try {
+ await installer.default(installer[name], forceDownload);
+ } catch (e) {
+ log.info(`Error installing ${name} extension: ${e.message}`);
+ }
}
- });
-};
+ },
-const toggleWindow = () => {
- if (window.isVisible()) {
- window.hide();
- } else {
- showWindow();
- }
-};
+ _createWindow: (): BrowserWindow => {
+ const contentHeight = 568;
+ let options = {
+ width: 320,
+ height: contentHeight,
+ resizable: false,
+ maximizable: false,
+ fullscreenable: false,
+ webPreferences: {
+ // prevents renderer process code from not running when window is hidden
+ backgroundThrottling: false,
+ // Enable experimental features
+ blinkFeatures: 'CSSBackdropFilter'
+ }
+ };
-const showWindow = () => {
- // position window based on tray icon location
- if(tray) {
- const { x, y } = getWindowPosition();
- window.setPosition(x, y, false);
- }
+ // setup window flags to mimic popover on macOS
+ if(isMacOS) {
+ options = Object.assign({}, options, {
+ height: contentHeight + 12, // 12 is the size of transparent area around arrow
+ frame: false,
+ transparent: true,
+ show: false
+ });
+ }
- window.show();
- window.focus();
-};
+ return new BrowserWindow(options);
+ },
-const getWindowPosition = () => {
- const windowBounds = window.getBounds();
- const trayBounds = tray.getBounds();
+ _setAppMenu: () => {
+ const template = [
+ {
+ label: 'Mullvad',
+ submenu: [
+ { role: 'about' },
+ { type: 'separator' },
+ { role: 'quit' }
+ ]
+ },
+ {
+ label: 'Edit',
+ submenu: [
+ { role: 'cut' },
+ { role: 'copy' },
+ { role: 'paste' },
+ { type: 'separator' },
+ { role: 'selectall' }
+ ]
+ }
+ ];
+ Menu.setApplicationMenu(Menu.buildFromTemplate(template));
+ },
- // center window horizontally below the tray icon
- const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2));
+ _addContextMenu: (window: BrowserWindow) => {
+ let menuTemplate = [
+ { role: 'cut' },
+ { role: 'copy' },
+ { role: 'paste' },
+ { type: 'separator' },
+ { role: 'selectall' }
+ ];
- // position window vertically below the tray icon
- const y = Math.round(trayBounds.y + trayBounds.height);
+ // add inspect element on right click menu
+ window.webContents.on('context-menu', (_e: Event, props: { x: number, y: number }) => {
+ let inspectTemplate = [{
+ label: 'Inspect element',
+ click() {
+ window.openDevTools({ mode: 'detach' });
+ window.inspectElement(props.x, props.y);
+ }
+ }];
- return { x, y };
-};
+ if(props.isEditable) {
+ let inputMenu = menuTemplate;
-const createTray = () => {
- tray = new Tray(nativeImage.createEmpty());
- tray.setHighlightMode('never');
- tray.on('click', toggleWindow);
+ // mixin 'inspect element' into standard menu when in development mode
+ if(isDevelopment) {
+ inputMenu = menuTemplate.concat([{type: 'separator'}], inspectTemplate);
+ }
- // setup NSEvent monitor to fix inconsistent window.blur
- // see https://github.com/electron/electron/issues/8689
- const { NSEventMonitor, NSEventMask } = require('nseventmonitor');
- const trayIconManager = new TrayIconManager(tray, 'unsecured');
- const macEventMonitor = new NSEventMonitor();
- const eventMask = NSEventMask.leftMouseDown | NSEventMask.rightMouseDown;
+ Menu.buildFromTemplate(inputMenu).popup(window);
+ } else if(isDevelopment) {
+ // display inspect element for all non-editable
+ // elements when in development mode
+ Menu.buildFromTemplate(inspectTemplate).popup(window);
+ }
+ });
+ },
- // add IPC handler to change tray icon from renderer
- ipcMain.on('changeTrayIcon', (_, type) => trayIconManager.iconType = type);
+ _toggleWindow: (window: BrowserWindow, tray: ?Tray) => {
+ if(window.isVisible()) {
+ window.hide();
+ } else {
+ appDelegate._showWindow(window, tray);
+ }
+ },
- // setup event handlers
- window.on('show', () => macEventMonitor.start(eventMask, () => window.hide()));
- window.on('hide', () => macEventMonitor.stop());
- window.on('close', () => window.closeDevTools());
- window.on('blur', () => !window.isDevToolsOpened() && window.hide());
-};
+ _showWindow: (window: BrowserWindow, tray: ?Tray) => {
+ // position window based on tray icon location
+ if(tray) {
+ const { x, y } = appDelegate._getWindowPosition(window, tray);
+ window.setPosition(x, y, false);
+ }
-app.on('window-all-closed', () => {
- app.quit();
-});
+ window.show();
+ window.focus();
+ },
-app.on('ready', async () => {
- createWindow();
+ _getWindowPosition: (window: BrowserWindow, tray: Tray): { x: number, y: number } => {
+ const windowBounds = window.getBounds();
+ const trayBounds = tray.getBounds();
- // create tray icon on macOS
- isMacOS && createTray();
+ // center window horizontally below the tray icon
+ const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2));
- createAppMenu();
- createContextMenu();
+ // position window vertically below the tray icon
+ const y = Math.round(trayBounds.y + trayBounds.height);
- if(isDevelopment) {
- await installDevTools();
- window.openDevTools({ mode: 'detach' });
- }
-});
+ return { x, y };
+ },
-const sendBackendInfo = () => {
- const file = './.mullvad_rpc_address';
- log.info('reading the ipc connection info from', file);
+ _createTray: (window: BrowserWindow): Tray => {
+ const tray = new Tray(nativeImage.createEmpty());
+ tray.setHighlightMode('never');
+ tray.on('click', () => appDelegate._toggleWindow(window, tray));
- fs.readFile(file, 'utf8', function (err,data) {
- if (err) {
- return log.info('Could not find backend connection info', err);
- }
+ // setup NSEvent monitor to fix inconsistent window.blur
+ // see https://github.com/electron/electron/issues/8689
+ const { NSEventMonitor, NSEventMask } = require('nseventmonitor');
+ const trayIconManager = new TrayIconManager(tray, 'unsecured');
+ const macEventMonitor = new NSEventMonitor();
+ const eventMask = NSEventMask.leftMouseDown | NSEventMask.rightMouseDown;
- log.info('Read IPC connection info', data);
- window.webContents.send('backend-info', {
- addr: data,
- });
- });
-};
+ // add IPC handler to change tray icon from renderer
+ ipcMain.on('changeTrayIcon', (_: Event, type: TrayIconType) => trayIconManager.iconType = type);
-const startBackend = () => {
- const pathToBackend = path.resolve(process.env.MULLVAD_BACKEND || '../talpid_core/target/debug/talpid_daemon');
- log.info('Starting the mullvad backend at', pathToBackend);
+ // setup event handlers
+ window.on('show', () => macEventMonitor.start(eventMask, () => window.hide()));
+ window.on('hide', () => macEventMonitor.stop());
+ window.on('close', () => window.closeDevTools());
+ window.on('blur', () => !window.isDevToolsOpened() && window.hide());
- const options = {
- name: 'mullvad backend',
- };
- sudo.exec(pathToBackend, options, (err) => {
- if (err && err.signal !== 'SIGINT') {
- log.info('Backend exited with error', err);
- } else {
- log.info('Backend exited');
- }
- });
+ return tray;
+ }
};
-if (isDevelopment) startBackend();
+
+appDelegate.setup();