diff options
| author | Andrej Mihajlov <and@codeispoetry.ru> | 2017-06-21 14:05:33 +0300 |
|---|---|---|
| committer | Andrej Mihajlov <and@codeispoetry.ru> | 2017-06-21 14:05:33 +0300 |
| commit | 7950d83c2d70c72bb08415d8ecf823d85ce7bd35 (patch) | |
| tree | f280e95a6caff7fe5ecf493444b1f0319465a3df /app | |
| parent | 9fd74d9e39df895d8bc2c8856c9a6ad807012560 (diff) | |
| parent | b441f6bb8956436fa64e6707c310013c126b826b (diff) | |
| download | mullvadvpn-7950d83c2d70c72bb08415d8ecf823d85ce7bd35.tar.xz mullvadvpn-7950d83c2d70c72bb08415d8ecf823d85ce7bd35.zip | |
Merge branch 'feature/refactor-main'
Diffstat (limited to 'app')
| -rw-r--r-- | app/main.js | 399 |
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(); |
