From 766858362a2f3e9f6bb85a0f21e56730524a6bc8 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Thu, 3 May 2018 22:24:42 +0200 Subject: [PATCH 01/10] Add fetching parity logic --- electron/cli/index.js | 70 +++++++ electron/config.json | 32 +++ electron/index.js | 97 +++++++++ electron/installers/windows/installer.nsh | 10 + electron/menu/index.js | 94 +++++++++ electron/messages/index.js | 20 ++ electron/operations/doesParityExist.js | 17 ++ electron/operations/fetchParity.js | 77 +++++++ electron/operations/handleError.js | 31 +++ electron/operations/runParity.js | 78 +++++++ electron/operations/signerNewToken.js | 31 +++ electron/utils/parityPath.js | 12 ++ package.json | 18 +- src/Receive/Receive.js | 4 +- src/Tokens/BalanceLayout/BalanceLayout.js | 3 +- src/Tokens/Tokens.js | 4 +- yarn.lock | 240 +++++++++++++++++++++- 17 files changed, 820 insertions(+), 18 deletions(-) create mode 100644 electron/cli/index.js create mode 100644 electron/config.json create mode 100644 electron/index.js create mode 100644 electron/installers/windows/installer.nsh create mode 100644 electron/menu/index.js create mode 100644 electron/messages/index.js create mode 100644 electron/operations/doesParityExist.js create mode 100644 electron/operations/fetchParity.js create mode 100644 electron/operations/handleError.js create mode 100644 electron/operations/runParity.js create mode 100644 electron/operations/signerNewToken.js create mode 100644 electron/utils/parityPath.js diff --git a/electron/cli/index.js b/electron/cli/index.js new file mode 100644 index 00000000..a7f6a8c6 --- /dev/null +++ b/electron/cli/index.js @@ -0,0 +1,70 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +// eslint-disable-next-line +const dynamicRequire = + typeof __non_webpack_require__ === 'undefined' + ? require + : __non_webpack_require__; // Dynamic require https://github.com/yargs/yargs/issues/781 + +const { app } = require('electron'); +const fs = require('fs'); +const omit = require('lodash/omit'); +const { spawn } = require('child_process'); + +const argv = dynamicRequire('yargs').argv; +const parityPath = require('../utils/parityPath'); +const { version } = require('../../package.json'); + +let parityArgv = null; // Args to pass to `parity` command + +/** + * Show output of `parity` command with args. The args are supposed to make + * parity stop, so that the output can be immediately shown on the terminal. + * + * @param {Array} args - The arguments to pass to `parity`. + */ +const showParityOutput = args => { + if (fs.existsSync(parityPath())) { + const parityHelp = spawn(parityPath(), args); + + parityHelp.stdout.on('data', data => console.log(data.toString())); + parityHelp.on('close', () => app.quit()); + } else { + console.log( + 'Please run Parity Light Wallet once to install Parity Light Client. This help message will then show all available commands.' + ); + app.quit(); + } + + return false; +}; + +module.exports = () => { + if (argv.help || argv.h) { + return showParityOutput(['--help']); + } + + if (argv.version || argv.v) { + console.log(`Parity UI version ${version}.`); + return showParityOutput(['--version']); + } + + // Used cached value if it exists + if (parityArgv) { + return [argv, parityArgv]; + } + + // Args to pass to `parity` command + parityArgv = omit(argv, '_', '$0', 'help', 'version'); + + // Delete all keys starting with --ui* from parityArgv. + // They will be handled directly by the UI. + Object.keys(parityArgv).forEach( + key => key.startsWith('ui') && delete parityArgv[key] + ); + + return [argv, parityArgv]; +}; diff --git a/electron/config.json b/electron/config.json new file mode 100644 index 00000000..ef0b51a3 --- /dev/null +++ b/electron/config.json @@ -0,0 +1,32 @@ +{ + "appId": "io.parity.light", + "directories": { + "buildResources": "./" + }, + "linux": { + "category": "Utility", + "icon": "./assets/icon/small-white-512x512.png", + "target": ["AppImage", "snap", "deb", "tar.xz"] + }, + "mac": { + "category": "public.app-category.productivity", + "icon": "./assets/icon/small-white-512x512.png", + "target": ["pkg"] + }, + "nsis": { + "include": "./electron/installers/windows/installer.nsh", + "oneClick": true, + "perMachine": true + }, + "pkg": { + "allowAnywhere": false, + "allowCurrentUserHome": false + }, + "productName": "Parity Light Wallet", + "publish": "github", + "win": { + "icon": "./assets/icon/small-white-512x512.png", + "publisherName": "Parity Technologies (UK) Ltd.", + "target": "nsis" + } +} diff --git a/electron/index.js b/electron/index.js new file mode 100644 index 00000000..7cd88d8a --- /dev/null +++ b/electron/index.js @@ -0,0 +1,97 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const electron = require('electron'); +const path = require('path'); +const url = require('url'); + +const addMenu = require('./menu'); +const cli = require('./cli'); +const doesParityExist = require('./operations/doesParityExist'); +const fetchParity = require('./operations/fetchParity'); +const handleError = require('./operations/handleError'); +const messages = require('./messages'); +const { runParity, killParity } = require('./operations/runParity'); + +const { app, BrowserWindow, ipcMain, session } = electron; +let mainWindow; + +// Get arguments from cli +const [argv] = cli(); + +function createWindow() { + // If cli() returns false, then it means that the arguments are stopping the + // app (e.g. --help or --version). We don't do anything more in this case. + if (!argv) { + return; + } + + mainWindow = new BrowserWindow({ + height: 800, + width: 1200 + }); + + doesParityExist() + .catch(() => fetchParity(mainWindow)) // Install parity if not present + .then(() => runParity(mainWindow)) + .catch(handleError); // Errors should be handled before, this is really just in case + + if (argv['ui-dev'] === true) { + // Opens http://127.0.0.1:3000 in --ui-dev mode + mainWindow.loadURL('http://127.0.0.1:3000'); + mainWindow.webContents.openDevTools(); + } else { + // Opens file:///path/to/.build/index.html in prod mode + mainWindow.loadURL( + url.format({ + pathname: path.join(__dirname, '..', '.build', 'index.html'), + protocol: 'file:', + slashes: true + }) + ); + } + + // Listen to messages from renderer process + ipcMain.on('asynchronous-message', messages); + + // Add application menu + addMenu(mainWindow); + + // 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) => { + details.requestHeaders.Origin = `parity://${mainWindow.id}.ui.parity`; + callback({ requestHeaders: details.requestHeaders }); + } + ); + + mainWindow.on('closed', () => { + mainWindow = null; + }); +} + +app.on('ready', createWindow); + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + killParity(); + app.quit(); + } +}); + +// Make sure parity stops when UI stops +app.on('before-quit', killParity); +app.on('will-quit', killParity); +app.on('quit', killParity); + +app.on('activate', () => { + if (mainWindow === null) { + createWindow(); + } +}); diff --git a/electron/installers/windows/installer.nsh b/electron/installers/windows/installer.nsh new file mode 100644 index 00000000..1d718cd8 --- /dev/null +++ b/electron/installers/windows/installer.nsh @@ -0,0 +1,10 @@ +; Change default install directory on Windows +; https://www.electron.build/configuration/nsis#how-do-change-the-default-installation-directory-to-custom +!macro preInit + SetRegView 64 + WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\Parity Technologies\Parity UI" + WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\Parity Technologies\Parity UI" + SetRegView 32 + WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\Parity Technologies\Parity UI" + WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\Parity Technologies\Parity UI" +!macroend diff --git a/electron/menu/index.js b/electron/menu/index.js new file mode 100644 index 00000000..0d5d7846 --- /dev/null +++ b/electron/menu/index.js @@ -0,0 +1,94 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const electron = require('electron'); + +const { app, Menu, shell } = electron; + +module.exports = mainWindow => { + // Create the Application's main menu + // https://github.com/electron/electron/blob/master/docs/api/menu.md#examples + const template = [ + { + label: 'Edit', + submenu: [ + { role: 'cut' }, + { role: 'copy' }, + { role: 'paste' }, + { role: 'delete' }, + { role: 'selectall' } + ] + }, + { + label: 'View', + submenu: [ + { role: 'reload' }, + { role: 'forcereload' }, + { role: 'toggledevtools' }, + { type: 'separator' }, + { role: 'resetzoom' }, + { role: 'zoomin' }, + { role: 'zoomout' }, + { type: 'separator' }, + { role: 'togglefullscreen' } + ] + }, + { + role: 'window', + submenu: [{ role: 'minimize' }, { role: 'close' }] + }, + { + role: 'help', + submenu: [ + { + label: 'Learn More', + click() { + shell.openExternal('https://parity.io'); + } + } + ] + } + ]; + + if (process.platform === 'darwin') { + template.unshift({ + label: app.getName(), + submenu: [ + { role: 'about' }, + { type: 'separator' }, + { role: 'services', submenu: [] }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideothers' }, + { role: 'unhide' }, + { type: 'separator' }, + { role: 'quit' } + ] + }); + + // Edit menu + template[1].submenu.push( + { type: 'separator' }, + { + label: 'Speech', + submenu: [{ role: 'startspeaking' }, { role: 'stopspeaking' }] + } + ); + + // Window menu + template[3].submenu = [ + { role: 'close' }, + { role: 'minimize' }, + { role: 'zoom' }, + { type: 'separator' }, + { role: 'front' } + ]; + } + + const menu = Menu.buildFromTemplate(template); + + Menu.setApplicationMenu(menu); + mainWindow.setAutoHideMenuBar(true); +}; diff --git a/electron/messages/index.js b/electron/messages/index.js new file mode 100644 index 00000000..b9fd367c --- /dev/null +++ b/electron/messages/index.js @@ -0,0 +1,20 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const { runParity } = require('../operations/runParity'); +const signerNewToken = require('../operations/signerNewToken'); + +/** + * Handle all asynchronous messages from renderer to main. + */ +module.exports = (event, arg) => { + switch (arg) { + case 'signer-new-token': { + signerNewToken(event); + break; + } + default: + } +}; diff --git a/electron/operations/doesParityExist.js b/electron/operations/doesParityExist.js new file mode 100644 index 00000000..8a5ebd10 --- /dev/null +++ b/electron/operations/doesParityExist.js @@ -0,0 +1,17 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const fs = require('fs'); +const util = require('util'); + +const parityPath = require('../utils/parityPath'); + +const fsExists = util.promisify(fs.stat); + +module.exports = () => + fsExists(parityPath()).then(() => { + // Global variables can be accessed in renderers via IPC + global.parityInstalled = true; + }); diff --git a/electron/operations/fetchParity.js b/electron/operations/fetchParity.js new file mode 100644 index 00000000..f555b555 --- /dev/null +++ b/electron/operations/fetchParity.js @@ -0,0 +1,77 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const { app, dialog } = require('electron'); +const axios = require('axios'); +const { download } = require('electron-dl'); +const fs = require('fs'); +const util = require('util'); + +const { + parity: { channel } +} = require('../../package.json'); +const parityPath = require('../utils/parityPath'); + +const fsExists = util.promisify(fs.stat); +const fsChmod = util.promisify(fs.chmod); + +const getArch = () => { + switch (process.platform) { + case 'darwin': + case 'win32': + return 'x86_64'; + default: { + switch (process.arch) { + case 'arm': + return 'arm'; + case 'arm64': + return 'aarch64'; + case 'x32': + return 'i686'; + default: + return 'x86_64'; + } + } + } +}; + +const getOs = () => { + switch (process.platform) { + case 'darwin': + return 'darwin'; + case 'win32': + return 'windows'; + default: + return 'linux'; + } +}; + +module.exports = mainWindow => { + // Download parity if not exist in userData + // Fetching from https://vanity-service.parity.io/parity-binaries + return fsExists(parityPath()) + .catch(() => + axios + .get( + `https://vanity-service.parity.io/parity-binaries?version=${channel}&os=${getOs()}&architecture=${getArch()}` + ) + .then(response => + response.data[0].files.find( + ({ name }) => name === 'parity' || name === 'parity.exe' + ) + ) + .then(({ downloadUrl }) => + download(mainWindow, downloadUrl, { + directory: app.getPath('userData'), + onProgress: progress => + mainWindow.webContents.send('parity-download-progress', progress) // Notify the renderers + }) + ) + ) + .then(() => fsChmod(parityPath(), '755')) + .catch(err => { + handleError(err, 'An error occured while fetching parity.'); + }); +}; diff --git a/electron/operations/handleError.js b/electron/operations/handleError.js new file mode 100644 index 00000000..7c85d4fa --- /dev/null +++ b/electron/operations/handleError.js @@ -0,0 +1,31 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const { dialog } = require('electron'); + +const { + parity: { channel } +} = require('../../package.json'); + +module.exports = (err, message = 'An error occurred.') => { + console.error(err); + dialog.showMessageBox( + { + buttons: ['OK'], + detail: `Please attach the following debugging info: +OS: ${process.platform} +Arch: ${process.arch} +Channel: ${channel} +Error: ${err.message} + +Please also attach the contents of the following file: +${parityPath()}.log`, + message: `${message} Please file an issue at https://github.com/parity-js/shell/issues.`, + title: 'Parity Error', + type: 'error' + }, + () => app.exit(1) + ); +}; diff --git a/electron/operations/runParity.js b/electron/operations/runParity.js new file mode 100644 index 00000000..9fbd5ee8 --- /dev/null +++ b/electron/operations/runParity.js @@ -0,0 +1,78 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const { app, dialog, webContents } = require('electron'); +const flatten = require('lodash/flatten'); +const fs = require('fs'); +const { spawn } = require('child_process'); +const util = require('util'); + +const cli = require('../cli'); +const handleError = require('./handleError'); +const parityPath = require('../utils/parityPath'); + +const [, parityArgv] = cli(); +const fsExists = util.promisify(fs.stat); +const fsReadFile = util.promisify(fs.readFile); +const fsUnlink = util.promisify(fs.unlink); + +let parity = null; // Will hold the running parity instance + +module.exports = { + runParity(mainWindow) { + // Create a logStream to save logs + const logFile = `${parityPath()}.log`; + + fsExists(logFile) + .then(() => fsUnlink(logFile)) + .catch(() => {}) + .then(() => { + var logStream = fs.createWriteStream(logFile, { flags: 'a' }); + + // Run an instance of parity if we receive the `run-parity` message + parity = spawn( + parityPath(), + flatten( + Object.keys(parityArgv).map(key => [`--${key}`, parityArgv[key]]) // Transform {arg: value} into [--arg, value] + ) + .concat('--light') + .filter(value => value !== true) // --arg true is equivalent to --arg + ); + + parity.stdout.pipe(logStream); + parity.stderr.pipe(logStream); + parity.on('error', err => { + throw new Error(err); + }); + parity.on('close', (exitCode, signal) => { + if (exitCode === 0) { + return; + } + + // If the exit code is not 0, then we show some error message + if (Object.keys(parityArgv).length) { + // If parity has been launched with some args, then most likely the + // args are wrong, so we show the output of parity. + return fsReadFile(logFile).then(data => + console.log(data.toString()) + ); + } else { + throw new Error(`Exit code ${exitCode}, with signal ${signal}.`); + } + }); + }) + .then(() => mainWindow.webContents.send('parity-running', true)) // Notify the renderers + .catch(err => { + handleError(err, 'An error occured while running parity.'); + }); + }, + killParity() { + if (parity) { + console.log('Stopping parity.'); + parity.kill(); + parity = null; + } + } +}; diff --git a/electron/operations/signerNewToken.js b/electron/operations/signerNewToken.js new file mode 100644 index 00000000..5471fdce --- /dev/null +++ b/electron/operations/signerNewToken.js @@ -0,0 +1,31 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const { spawn } = require('child_process'); + +const parityPath = require('../utils/parityPath'); + +module.exports = event => { + // Generate a new token + const paritySigner = spawn(parityPath(), ['signer', 'new-token']); + + // Listen to the output of the previous command + paritySigner.stdout.on('data', data => { + // If the output line is xxxx-xxxx-xxxx-xxxx, then it's our token + const match = data + .toString() + .match( + /[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}/ + ); + + if (match) { + const token = match[0]; + + // Send back the token to the renderer process + event.sender.send('asynchronous-reply', token); + paritySigner.kill(); // We don't need the signer anymore + } + }); +}; diff --git a/electron/utils/parityPath.js b/electron/utils/parityPath.js new file mode 100644 index 00000000..89f4b99c --- /dev/null +++ b/electron/utils/parityPath.js @@ -0,0 +1,12 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +const { app } = require('electron'); + +const parityPath = `${app.getPath('userData')}/parity${ + process.platform === 'win32' ? '.exe' : '' +}`; + +module.exports = () => parityPath; diff --git a/package.json b/package.json index 802b4d1f..e13a85b8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "light", "description": "The Parity Light Wallet", "version": "1.0.0", - "main": "build/index.js", + "main": "build/electron.js", "author": "Parity Team ", "maintainers": [ "Jaco Greeff", @@ -22,12 +22,17 @@ "Parity", "Promise" ], + "parity": { + "channel": "beta" + }, "scripts": { - "build": "npm run build-css && npm run build-js", + "build": "npm run build-css && npm run build-js && npm run build-electron", "build-css": "node-sass-chokidar src/ -o src/", + "build-electron": "webpack --config electron/webpack.config.js", "build-js": "react-app-rewired build", "lint": "semistandard 'src/**/*.js' --parser babel-eslint", - "start": "npm-run-all -p watch-css start-js", + "start": "npm-run-all -p watch-css start-js start-electron", + "start-electron": "electron electron/ --ui-dev", "start-js": "react-app-rewired start", "test": "echo Skipped.", "watch-css": "npm run build-css -- --watch --recursive" @@ -35,12 +40,17 @@ "dependencies": { "@parity/api": "^2.1.22", "@parity/light.js": "github:parity-js/light.js#5a562b07ff3f7216e652c9e3944521d0e853ea56", + "axios": "^0.18.0", + "electron": "^2.0.0", + "electron-dl": "^1.11.0", + "lodash": "^4.17.10", "mobx": "^4.2.0", "mobx-react": "^5.1.2", "react": "^16.3.2", "react-dom": "^16.3.2", "react-router-dom": "^4.2.2", - "react-scripts": "1.1.4" + "react-scripts": "1.1.4", + "yargs": "^11.0.0" }, "devDependencies": { "babel-eslint": "^8.2.3", diff --git a/src/Receive/Receive.js b/src/Receive/Receive.js index e59878ac..fafe73b7 100644 --- a/src/Receive/Receive.js +++ b/src/Receive/Receive.js @@ -4,12 +4,12 @@ // SPDX-License-Identifier: MIT import React, { Component } from 'react'; -import { me$ } from '@parity/light.js'; +import { defaultAccount$ } from '@parity/light.js'; import light from '../hoc'; @light({ - me: me$ + me: defaultAccount$ }) class Receive extends Component { render () { diff --git a/src/Tokens/BalanceLayout/BalanceLayout.js b/src/Tokens/BalanceLayout/BalanceLayout.js index f4817607..8ad53d83 100644 --- a/src/Tokens/BalanceLayout/BalanceLayout.js +++ b/src/Tokens/BalanceLayout/BalanceLayout.js @@ -14,7 +14,8 @@ const BalanceLayout = ({ balance, image, name, symbol }) => (
{name}
- {balance ? (balance / ETHER_IN_WEI).toFixed(2) : '...'} {symbol} + {Number.isFinite(balance) ? (balance / ETHER_IN_WEI).toFixed(2) : '...'}{' '} + {symbol}
); diff --git a/src/Tokens/Tokens.js b/src/Tokens/Tokens.js index b5a9a0bb..ad943f00 100644 --- a/src/Tokens/Tokens.js +++ b/src/Tokens/Tokens.js @@ -5,7 +5,7 @@ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; -import { me$ } from '@parity/light.js'; +import { defaultAccount$ } from '@parity/light.js'; import EthBalance from './EthBalance'; import light from '../hoc'; @@ -14,7 +14,7 @@ import TokenBalance from './TokenBalance'; @inject('tokensStore') @observer @light({ - me: me$ + me: defaultAccount$ }) class Tokens extends Component { render () { diff --git a/yarn.lock b/yarn.lock index 6d0df217..964a3682 100644 --- a/yarn.lock +++ b/yarn.lock @@ -108,7 +108,7 @@ version "2.1.6" resolved "https://registry.yarnpkg.com/@parity/jsonrpc/-/jsonrpc-2.1.6.tgz#260bbe7dfcec18d59f0bf1668dfd6021452d6452" -"@parity/light.js@github:parity-js/light.js", "@parity/light.js@github:parity-js/light.js#5a562b07ff3f7216e652c9e3944521d0e853ea56": +"@parity/light.js@github:parity-js/light.js#5a562b07ff3f7216e652c9e3944521d0e853ea56": version "1.0.0" resolved "https://codeload.github.com/parity-js/light.js/tar.gz/5a562b07ff3f7216e652c9e3944521d0e853ea56" dependencies: @@ -121,6 +121,10 @@ version "1.1.0" resolved "https://registry.yarnpkg.com/@parity/wordlist/-/wordlist-1.1.0.tgz#9e9ed3ab7837f5633b5844e60a355e9e63e427ae" +"@types/node@^8.0.24": + version "8.10.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.11.tgz#971ea8cb91adbe0b74e3fbd867dec192d5893a5f" + abab@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" @@ -465,6 +469,13 @@ aws4@^1.2.1, aws4@^1.6.0: version "1.7.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" +axios@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" + dependencies: + follow-redirects "^1.3.0" + is-buffer "^1.1.5" + axobject-query@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-0.1.0.tgz#62f59dbc59c9f9242759ca349960e7a2fe3c36c0" @@ -1655,6 +1666,14 @@ cliui@^3.2.0: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" @@ -1760,6 +1779,14 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" +concat-stream@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" @@ -2067,7 +2094,7 @@ debug-log@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" -debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2341,10 +2368,40 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +electron-dl@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/electron-dl/-/electron-dl-1.11.0.tgz#112851f3857bb1a556b5c736af06040bd40df850" + dependencies: + ext-name "^5.0.0" + pupa "^1.0.0" + unused-filename "^1.0.0" + +electron-download@^3.0.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-3.3.0.tgz#2cfd54d6966c019c4d49ad65fbe65cc9cdef68c8" + dependencies: + debug "^2.2.0" + fs-extra "^0.30.0" + home-path "^1.0.1" + minimist "^1.2.0" + nugget "^2.0.0" + path-exists "^2.1.0" + rc "^1.1.2" + semver "^5.3.0" + sumchecker "^1.2.0" + electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30: version "1.3.45" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.45.tgz#458ac1b1c5c760ce8811a16d2bfbd97ec30bafb8" +electron@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/electron/-/electron-2.0.0.tgz#e95dc7f3a089a52b8c2a52c7c9e1024db0c8d46e" + dependencies: + "@types/node" "^8.0.24" + electron-download "^3.0.1" + extract-zip "^1.0.3" + elliptic@^6.0.0: version "6.4.0" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" @@ -2880,6 +2937,19 @@ express@^4.13.3: utils-merge "1.0.1" vary "~1.1.2" +ext-list@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" + dependencies: + mime-db "^1.28.0" + +ext-name@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" + dependencies: + ext-list "^2.0.0" + sort-keys-length "^1.0.0" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -2933,6 +3003,15 @@ extract-text-webpack-plugin@3.0.2: schema-utils "^0.3.0" webpack-sources "^1.0.1" +extract-zip@^1.0.3: + version "1.6.6" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" + dependencies: + concat-stream "1.6.0" + debug "2.6.9" + mkdirp "0.5.0" + yauzl "2.4.1" + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -2993,6 +3072,12 @@ fbjs@^0.8.16: setimmediate "^1.0.5" ua-parser-js "^0.7.9" +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -3105,7 +3190,7 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -follow-redirects@^1.0.0: +follow-redirects@^1.0.0, follow-redirects@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.4.1.tgz#d8120f4518190f55aac65bb6fc7b85fcd666d6aa" dependencies: @@ -3564,6 +3649,10 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" +home-path@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/home-path/-/home-path-1.0.5.tgz#788b29815b12d53bacf575648476e6f9041d133f" + homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" @@ -4744,7 +4833,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4: +"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -4869,7 +4958,7 @@ memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" -meow@^3.3.0, meow@^3.7.0: +meow@^3.1.0, meow@^3.3.0, meow@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" dependencies: @@ -4939,7 +5028,7 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: +"mime-db@>= 1.33.0 < 2", mime-db@^1.28.0, mime-db@~1.33.0: version "1.33.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" @@ -5013,6 +5102,12 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -5030,6 +5125,10 @@ mobx@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/mobx/-/mobx-4.2.0.tgz#ee0b0a4f3da2f4776225046ab208ac329a4841d4" +modify-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/modify-filename/-/modify-filename-1.1.0.tgz#9a2dec83806fbb2d975f22beec859ca26b393aa1" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -5309,6 +5408,18 @@ nth-check@~1.0.1: dependencies: boolbase "~1.0.0" +nugget@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" + dependencies: + debug "^2.1.3" + minimist "^1.1.0" + pretty-bytes "^1.0.2" + progress-stream "^1.1.0" + request "^2.45.0" + single-line-log "^1.1.2" + throttleit "0.0.2" + num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" @@ -5345,6 +5456,10 @@ object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -5558,7 +5673,7 @@ path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" -path-exists@^2.0.0: +path-exists@^2.0.0, path-exists@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: @@ -5630,6 +5745,10 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -5991,6 +6110,13 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +pretty-bytes@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" + dependencies: + get-stdin "^4.0.1" + meow "^3.1.0" + pretty-bytes@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9" @@ -6021,6 +6147,13 @@ process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" +progress-stream@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" + dependencies: + speedometer "~0.1.2" + through2 "~0.2.3" + progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" @@ -6088,6 +6221,10 @@ punycode@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" +pupa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-1.0.0.tgz#9a9568a5af7e657b8462a6e9d5328743560ceff6" + q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -6162,7 +6299,7 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" -rc@^1.0.1, rc@^1.1.6, rc@^1.1.7: +rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.1.7: version "1.2.7" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.7.tgz#8a10ca30d588d00464360372b890d06dacd02297" dependencies: @@ -6360,6 +6497,15 @@ readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readdirp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" @@ -6496,7 +6642,7 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2, request@^2.79.0: +request@2, request@^2.45.0, request@^2.79.0: version "2.85.0" resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" dependencies: @@ -6886,6 +7032,12 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" +single-line-log@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" + dependencies: + string-width "^1.0.1" + slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -6953,6 +7105,12 @@ sockjs@0.3.18: faye-websocket "^0.10.0" uuid "^2.0.2" +sort-keys-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" + dependencies: + sort-keys "^1.0.0" + sort-keys@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" @@ -7042,6 +7200,10 @@ spdy@^3.4.1: select-hose "^2.0.0" spdy-transport "^2.0.18" +speedometer@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" + split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -7219,6 +7381,13 @@ style-loader@0.19.0: loader-utils "^1.0.2" schema-utils "^0.3.0" +sumchecker@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-1.3.1.tgz#79bb3b4456dd04f18ebdbc0d703a1d1daec5105d" + dependencies: + debug "^2.2.0" + es6-promise "^4.0.5" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -7357,6 +7526,17 @@ throat@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/throat/-/throat-3.2.0.tgz#50cb0670edbc40237b9e347d7e1f88e4620af836" +throttleit@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" + +through2@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" + dependencies: + readable-stream "~1.1.9" + xtend "~2.1.1" + through@2, through@^2.3.6, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -7579,6 +7759,13 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" +unused-filename@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unused-filename/-/unused-filename-1.0.0.tgz#d340880f71ae2115ebaa1325bef05cc6684469c6" + dependencies: + modify-filename "^1.1.0" + path-exists "^3.0.0" + unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" @@ -7979,6 +8166,12 @@ xtend@^4.0.0, xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" +xtend@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + dependencies: + object-keys "~0.4.0" + y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" @@ -8013,6 +8206,29 @@ yargs-parser@^7.0.0: dependencies: camelcase "^4.1.0" +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + +yargs@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + yargs@^6.6.0: version "6.6.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" @@ -8075,3 +8291,9 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" + +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + dependencies: + fd-slicer "~1.0.1" -- GitLab From 0f92c6f45ea445184de55fb15c678ac325061c40 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 4 May 2018 09:17:53 +0200 Subject: [PATCH 02/10] Add node health and sync explanations --- src/Tokens/Tokens.js | 61 ++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/src/Tokens/Tokens.js b/src/Tokens/Tokens.js index ad943f00..d611d106 100644 --- a/src/Tokens/Tokens.js +++ b/src/Tokens/Tokens.js @@ -5,7 +5,7 @@ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; -import { defaultAccount$ } from '@parity/light.js'; +import { defaultAccount$, nodeHealth$ } from '@parity/light.js'; import EthBalance from './EthBalance'; import light from '../hoc'; @@ -14,31 +14,58 @@ import TokenBalance from './TokenBalance'; @inject('tokensStore') @observer @light({ - me: defaultAccount$ + me: defaultAccount$, + nodeHealth: nodeHealth$ }) class Tokens extends Component { - render () { + render() { const { me, + nodeHealth, tokensStore: { tokens } } = this.props; - if (!me) { - return null; - } - return ( -
-
    - {Array.from(tokens.keys()).map(key => ( -
  • - {key === 'ETH' ? ( - - ) : ( - - )} +
    +
      + {me && + Array.from(tokens.keys()).map(key => ( +
    • + {key === 'ETH' ? ( + + ) : ( + + )} +
    • + ))} + {nodeHealth && ( +
    • +

      2. Overall node health status

      +
      +                PEERS: {nodeHealth.peers.status} {nodeHealth.peers.details[0]}/{
      +                  nodeHealth.peers.details[1]
      +                }
      +                
      SYNC: {nodeHealth.sync.status} +
      TIMESYNC: {nodeHealth.time.status} +
      +

      + Note: I can make a small algorithm which outputs the average + health with 3 states: OK, ALRIGHT, and BAD +

      +
    • + )} + {nodeHealth && ( +
    • +

      + 3. When SYNC above is false, we have the syncing progress to + give an idea how much time it'll take +

      +
      +                "startingBlock": 900
      "currentBlock": 902
      + "highestBlock": 1108 +
    • - ))} + )}
    ); -- GitLab From dd2e6f7e2bde0790fac28cbd63cd971e688e24fe Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 4 May 2018 09:41:12 +0200 Subject: [PATCH 03/10] Show dl & install parity status --- electron/operations/doesParityExist.js | 6 +--- electron/operations/fetchParity.js | 39 ++++++++++------------- package.json | 3 +- src/Tokens/Tokens.js | 44 ++++++++++++++++++++++++-- yarn.lock | 4 +++ 5 files changed, 65 insertions(+), 31 deletions(-) diff --git a/electron/operations/doesParityExist.js b/electron/operations/doesParityExist.js index 8a5ebd10..a8f4e064 100644 --- a/electron/operations/doesParityExist.js +++ b/electron/operations/doesParityExist.js @@ -10,8 +10,4 @@ const parityPath = require('../utils/parityPath'); const fsExists = util.promisify(fs.stat); -module.exports = () => - fsExists(parityPath()).then(() => { - // Global variables can be accessed in renderers via IPC - global.parityInstalled = true; - }); +module.exports = () => fsExists(parityPath()); diff --git a/electron/operations/fetchParity.js b/electron/operations/fetchParity.js index f555b555..4f7c0247 100644 --- a/electron/operations/fetchParity.js +++ b/electron/operations/fetchParity.js @@ -48,30 +48,25 @@ const getOs = () => { } }; -module.exports = mainWindow => { - // Download parity if not exist in userData - // Fetching from https://vanity-service.parity.io/parity-binaries - return fsExists(parityPath()) - .catch(() => - axios - .get( - `https://vanity-service.parity.io/parity-binaries?version=${channel}&os=${getOs()}&architecture=${getArch()}` - ) - .then(response => - response.data[0].files.find( - ({ name }) => name === 'parity' || name === 'parity.exe' - ) - ) - .then(({ downloadUrl }) => - download(mainWindow, downloadUrl, { - directory: app.getPath('userData'), - onProgress: progress => - mainWindow.webContents.send('parity-download-progress', progress) // Notify the renderers - }) - ) +// Fetch parity from https://vanity-service.parity.io/parity-binaries +module.exports = mainWindow => + axios + .get( + `https://vanity-service.parity.io/parity-binaries?version=${channel}&os=${getOs()}&architecture=${getArch()}` + ) + .then(response => + response.data[0].files.find( + ({ name }) => name === 'parity' || name === 'parity.exe' + ) + ) + .then(({ downloadUrl }) => + download(mainWindow, downloadUrl, { + directory: app.getPath('userData'), + onProgress: progress => + mainWindow.webContents.send('parity-download-progress', progress) // Notify the renderers + }) ) .then(() => fsChmod(parityPath(), '755')) .catch(err => { handleError(err, 'An error occured while fetching parity.'); }); -}; diff --git a/package.json b/package.json index e13a85b8..bb67d409 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "build-electron": "webpack --config electron/webpack.config.js", "build-js": "react-app-rewired build", "lint": "semistandard 'src/**/*.js' --parser babel-eslint", - "start": "npm-run-all -p watch-css start-js start-electron", + "start": "npm-run-all -p watch-css start-js", "start-electron": "electron electron/ --ui-dev", "start-js": "react-app-rewired start", "test": "echo Skipped.", @@ -43,6 +43,7 @@ "axios": "^0.18.0", "electron": "^2.0.0", "electron-dl": "^1.11.0", + "is-electron": "^2.1.0", "lodash": "^4.17.10", "mobx": "^4.2.0", "mobx-react": "^5.1.2", diff --git a/src/Tokens/Tokens.js b/src/Tokens/Tokens.js index d611d106..dc99f174 100644 --- a/src/Tokens/Tokens.js +++ b/src/Tokens/Tokens.js @@ -5,12 +5,18 @@ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; +import isElectron from 'is-electron'; import { defaultAccount$, nodeHealth$ } from '@parity/light.js'; import EthBalance from './EthBalance'; import light from '../hoc'; import TokenBalance from './TokenBalance'; +let electron; +if (isElectron()) { + electron = window.require('electron'); +} + @inject('tokensStore') @observer @light({ @@ -18,16 +24,38 @@ import TokenBalance from './TokenBalance'; nodeHealth: nodeHealth$ }) class Tokens extends Component { - render() { + state = { + progress: 0, + status: null + }; + + componentDidMount () { + if (!isElectron()) { + return; + } + + const { ipcRenderer } = electron; + + // Listen to messages from main process + ipcRenderer.on('parity-download-progress', (_, progress) => { + this.setState({ progress, status: 'Downloading...' }); + }); + ipcRenderer.on('parity-running', (_, running) => { + this.setState({ status: 'Parity running...' }); + }); + } + + render () { const { me, nodeHealth, tokensStore: { tokens } } = this.props; + const { progress, status } = this.state; return ( -
    -
      +
      +
        {me && Array.from(tokens.keys()).map(key => (
      • @@ -38,6 +66,16 @@ class Tokens extends Component { )}
      • ))} +
      • +

        1. DL and install parity Status

        + {nodeHealth ? ( +
        OK, parity installed and running
        + ) : ( +
        +                progress: {Math.round(progress * 100)}%
        status: {status} +
        + )} +
      • {nodeHealth && (
      • 2. Overall node health status

        diff --git a/yarn.lock b/yarn.lock index 964a3682..bcb98e70 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4000,6 +4000,10 @@ is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" +is-electron@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.1.0.tgz#37dd2e9e7167efa8bafce86c0c25762bc4b851fa" + is-equal-shallow@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" -- GitLab From 0baf16754d4e1ffa87065392d6d894d8db1fd66f Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 4 May 2018 12:51:00 +0200 Subject: [PATCH 04/10] Add download parity progress in onboarding --- electron/operations/runParity.js | 6 +- src/App/App.js | 17 +++++- src/Onboarding/Onboarding.js | 53 ++++++++++++++++++ src/Onboarding/index.js | 8 +++ src/Tokens/Tokens.js | 41 ++------------ src/stores/ElectronStore.js | 95 ++++++++++++++++++++++++++++++++ src/stores/index.js | 2 + 7 files changed, 185 insertions(+), 37 deletions(-) create mode 100644 src/Onboarding/Onboarding.js create mode 100644 src/Onboarding/index.js create mode 100644 src/stores/ElectronStore.js diff --git a/electron/operations/runParity.js b/electron/operations/runParity.js index 9fbd5ee8..bbf6021c 100644 --- a/electron/operations/runParity.js +++ b/electron/operations/runParity.js @@ -63,7 +63,11 @@ module.exports = { } }); }) - .then(() => mainWindow.webContents.send('parity-running', true)) // Notify the renderers + .then(() => { + // Notify the renderers + mainWindow.webContents.send('parity-running', true); + global.isParityRunning = true; // Send this variable to renderes via IPC + }) .catch(err => { handleError(err, 'An error occured while running parity.'); }); diff --git a/src/App/App.js b/src/App/App.js index 89f0b8da..5c9023a8 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -4,15 +4,28 @@ // SPDX-License-Identifier: MIT import React, { Component } from 'react'; -import { BrowserRouter as Router, Route, Link } from 'react-router-dom'; +import { + BrowserRouter as Router, + Redirect, + Route, + Link +} from 'react-router-dom'; +import { inject, observer } from 'mobx-react'; +import Onboarding from '../Onboarding'; import Send from '../Send'; import Receive from '../Receive'; import Tokens from '../Tokens'; import './App.css'; +@inject('electronStore') +@observer class App extends Component { render () { + const { + electronStore: { isReady } + } = this.props; + return (
        @@ -23,7 +36,9 @@ class App extends Component {
        + {!isReady && } + diff --git a/src/Onboarding/Onboarding.js b/src/Onboarding/Onboarding.js new file mode 100644 index 00000000..fd3b672c --- /dev/null +++ b/src/Onboarding/Onboarding.js @@ -0,0 +1,53 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +import React, { Component } from 'react'; +import { inject, observer } from 'mobx-react'; +import { Redirect } from 'react-router-dom'; + +@inject('electronStore') +@observer +class Onboarding extends Component { + render() { + const { + electronStore: { downloadProgress, isReady } + } = this.props; + + if (isReady) { + return ; + } + + return ( +
        +

        + This is the Onboarding page.
        +

        +
          +
        • +

          1. DL and install parity

          +
          +              progress: {Math.round(downloadProgress * 100)}%
          status:{' '} + {this.renderStatus()} +
          +
        • +
        +
        + ); + } + + renderStatus = () => { + const { + electronStore: { isParityRunning } + } = this.props; + + if (isParityRunning) { + return 'Running parity...'; + } else { + return 'Downloading...'; + } + }; +} + +export default Onboarding; diff --git a/src/Onboarding/index.js b/src/Onboarding/index.js new file mode 100644 index 00000000..ac178853 --- /dev/null +++ b/src/Onboarding/index.js @@ -0,0 +1,8 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +import Onboarding from './Onboarding'; + +export default Onboarding; diff --git a/src/Tokens/Tokens.js b/src/Tokens/Tokens.js index dc99f174..b638674b 100644 --- a/src/Tokens/Tokens.js +++ b/src/Tokens/Tokens.js @@ -5,18 +5,12 @@ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; -import isElectron from 'is-electron'; import { defaultAccount$, nodeHealth$ } from '@parity/light.js'; import EthBalance from './EthBalance'; import light from '../hoc'; import TokenBalance from './TokenBalance'; -let electron; -if (isElectron()) { - electron = window.require('electron'); -} - @inject('tokensStore') @observer @light({ @@ -24,34 +18,12 @@ if (isElectron()) { nodeHealth: nodeHealth$ }) class Tokens extends Component { - state = { - progress: 0, - status: null - }; - - componentDidMount () { - if (!isElectron()) { - return; - } - - const { ipcRenderer } = electron; - - // Listen to messages from main process - ipcRenderer.on('parity-download-progress', (_, progress) => { - this.setState({ progress, status: 'Downloading...' }); - }); - ipcRenderer.on('parity-running', (_, running) => { - this.setState({ status: 'Parity running...' }); - }); - } - render () { const { me, nodeHealth, tokensStore: { tokens } } = this.props; - const { progress, status } = this.state; return (
        @@ -66,16 +38,14 @@ class Tokens extends Component { )}
      • ))} + + {/* @brian the following 3
      • are just to show what data I have from the backend, remove them whenever you want */}
      • 1. DL and install parity Status

        - {nodeHealth ? ( -
        OK, parity installed and running
        - ) : ( -
        -                progress: {Math.round(progress * 100)}%
        status: {status} -
        - )} + +
        OK, parity installed and running
      • + {nodeHealth && (
      • 2. Overall node health status

        @@ -92,6 +62,7 @@ class Tokens extends Component {

      • )} + {nodeHealth && (
      • diff --git a/src/stores/ElectronStore.js b/src/stores/ElectronStore.js new file mode 100644 index 00000000..b201c7cd --- /dev/null +++ b/src/stores/ElectronStore.js @@ -0,0 +1,95 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: MIT + +import { computed, action, observable } from 'mobx'; +import isElectron from 'is-electron'; +import store from 'store'; + +import ethereumIcon from '../assets/img/tokens/ethereum.png'; + +const electron = isElectron() ? window.require('electron') : null; + +const LS_PREFIX = '__paritylight::'; +const LS_KEY = `${LS_PREFIX}secureToken`; + +export default class ElectronStore { + @observable downloadProgress = 0; + @observable isParityRunning = false; + @observable token = null; + + constructor () { + // Retrieve token from localStorage + const token = store.get(LS_KEY); + if (token) { + this.setToken(token); + } + + if (!electron) { + console.log( + 'Not in Electron, ElectronStore will only have limited capabilities.' + ); + return; + } + + const { ipcRenderer, remote } = electron; + + // Set/Update isParityRunning + this.setIsParityRunning(!!remote.getGlobal('isParityRunning')); + ipcRenderer.on('parity-running', (_, isParityRunning) => { + this.setIsParityRunning(isParityRunning); + + // Request new token if there's none + if (!token) { + this.requestNewToken(); + } + }); + + // Set download progress + ipcRenderer.on('parity-download-progress', (_, progress) => { + this.setDownloadProgress(progress); + }); + } + + /** + * Tell the app that we're ready to connect to the api + */ + @computed + get isReady () { + return !!this.token && (electron ? this.isParityRunning : true); + } + + requestNewToken = () => { + const { ipcRenderer } = electron; + + // Request new token from Electron + ipcRenderer.send('asynchronous-message', 'signer-new-token'); + ipcRenderer.once('asynchronous-reply', (_, token) => { + if (!token) { + return; + } + // If `parity signer new-token` has successfully given us a token back, + // then we submit it + this.setToken(token); + }); + }; + + @action + setDownloadProgress = downloadProgress => { + this.downloadProgress = downloadProgress; + }; + + @action + setIsParityRunning = isParityRunning => { + this.isParityRunning = isParityRunning; + }; + + @action + setToken = token => { + this.token = token; + this.updateLS(); + }; + + updateLS = () => store.set(LS_KEY, this.token); +} diff --git a/src/stores/index.js b/src/stores/index.js index 9207a463..51b8ccd4 100644 --- a/src/stores/index.js +++ b/src/stores/index.js @@ -3,8 +3,10 @@ // // SPDX-License-Identifier: MIT +import ElectronStore from './ElectronStore'; import TokensStore from './TokensStore'; export default { + electronStore: new ElectronStore(), tokensStore: new TokensStore() }; -- GitLab From f7484423cf9da80218077412d8e595be6fad7978 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 4 May 2018 15:26:14 +0200 Subject: [PATCH 05/10] Add isApiConnected --- electron/cli/index.js | 20 ++++-- package.json | 2 +- src/App/App.js | 35 +++++----- .../Onboarding.js => Loading/Loading.js} | 16 ++--- src/{Onboarding => Loading}/index.js | 4 +- src/Tokens/Tokens.js | 14 ++-- src/index.js | 6 -- .../{ElectronStore.js => ParityStore.js} | 65 +++++++++++++++---- src/stores/index.js | 4 +- 9 files changed, 107 insertions(+), 59 deletions(-) rename src/{Onboarding/Onboarding.js => Loading/Loading.js} (75%) rename src/{Onboarding => Loading}/index.js (64%) rename src/stores/{ElectronStore.js => ParityStore.js} (57%) diff --git a/electron/cli/index.js b/electron/cli/index.js index a7f6a8c6..7b88f5b3 100644 --- a/electron/cli/index.js +++ b/electron/cli/index.js @@ -60,11 +60,21 @@ module.exports = () => { // Args to pass to `parity` command parityArgv = omit(argv, '_', '$0', 'help', 'version'); - // Delete all keys starting with --ui* from parityArgv. - // They will be handled directly by the UI. - Object.keys(parityArgv).forEach( - key => key.startsWith('ui') && delete parityArgv[key] - ); + // Sanitize args to be easily used by parity + Object.keys(parityArgv).forEach(key => { + // Delete all keys starting with --ui* from parityArgv. + // They will be handled directly by the UI. + if (key.startsWith('ui')) { + delete parityArgv[key]; + } + + // yargs create camelCase keys for each arg, e.g. "--ws-origins all" will + // create { wsOrigins: 'all' }. For parity, we remove all those that have + // a capital letter + if (/[A-Z]/.test(key)) { + delete parityArgv[key]; + } + }); return [argv, parityArgv]; }; diff --git a/package.json b/package.json index bb67d409..c92ef487 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "build-js": "react-app-rewired build", "lint": "semistandard 'src/**/*.js' --parser babel-eslint", "start": "npm-run-all -p watch-css start-js", - "start-electron": "electron electron/ --ui-dev", + "start-electron": "electron electron/ --ui-dev --ws-origins all", "start-js": "react-app-rewired start", "test": "echo Skipped.", "watch-css": "npm run build-css -- --watch --recursive" diff --git a/src/App/App.js b/src/App/App.js index 5c9023a8..fe16a192 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -12,41 +12,40 @@ import { } from 'react-router-dom'; import { inject, observer } from 'mobx-react'; -import Onboarding from '../Onboarding'; +import Loading from '../Loading'; import Send from '../Send'; import Receive from '../Receive'; import Tokens from '../Tokens'; import './App.css'; -@inject('electronStore') +@inject('parityStore') @observer class App extends Component { - render () { + render() { const { - electronStore: { isReady } + parityStore: { isReady } } = this.props; return ( -

        -
        -
        - - +
        +
        +
        + +
        -
        - {!isReady && } - - - - +
        + + + + -