Skip to content

Commit

Permalink
Merge pull request #536 from cosmos/fabo/498-full-page-error-on-crash
Browse files Browse the repository at this point in the history
Show full page error on crash
  • Loading branch information
faboweb authored Mar 7, 2018
2 parents 942333e + 1cc35ed commit ef9cb95
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 125 deletions.
51 changes: 26 additions & 25 deletions app/src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ function expectCleanExit (process, errorMessage = 'Process exited unplanned') {
})
}

function handleCrash (error) {
mainWindow.loadURL(winURL + '?node=' + nodeIP + '&error=' + error.message)
}

function shutdown () {
if (shuttingDown) return

Expand Down Expand Up @@ -157,15 +161,15 @@ function startProcess (name, args, env) {
if (process.env.BINARY_PATH) {
binPath = process.env.BINARY_PATH
} else
if (DEV) {
// in dev mode or tests, use binaries installed in GOPATH
let GOPATH = process.env.GOPATH
if (!GOPATH) GOPATH = join(home, 'go')
binPath = join(GOPATH, 'bin', name)
} else {
// in production mode, use binaries packaged with app
binPath = join(__dirname, '..', 'bin', name)
}
if (DEV) {
// in dev mode or tests, use binaries installed in GOPATH
let GOPATH = process.env.GOPATH
if (!GOPATH) GOPATH = join(home, 'go')
binPath = join(GOPATH, 'bin', name)
} else {
// in production mode, use binaries packaged with app
binPath = join(__dirname, '..', 'bin', name)
}

let argString = args.map((arg) => JSON.stringify(arg)).join(' ')
log(`spawning ${binPath} with args "${argString}"`)
Expand All @@ -184,8 +188,7 @@ function startProcess (name, args, env) {
await new Promise(resolve => Raven.captureException(err, resolve))
// if we throw errors here, they are not handled by the main process
console.error('[Uncaught Exception] Child', name, 'produced an unhandled exception:', err)
console.log('Shutting down UI')
shutdown()
handleCrash(err)
}
})
return child
Expand Down Expand Up @@ -309,15 +312,13 @@ if (!TEST) {
await sleep(1000)
logError('[Uncaught Exception]', err)
await new Promise(resolve => Raven.captureException(err, resolve))
await shutdown()
process.exit(1)
handleCrash(err)
})
process.on('unhandledRejection', async function (err) {
await sleep(1000)
logError('[Unhandled Promise Rejection]', err)
await new Promise(resolve => Raven.captureException(err, resolve))
await shutdown()
process.exit(1)
handleCrash(err)
})
}

Expand Down Expand Up @@ -376,7 +377,7 @@ async function reconnect (seeds) {
let nodeAlive = false
while (!nodeAlive) {
let nodeIP = pickNode(seeds)
nodeAlive = await axios('http://' + nodeIP, {timeout: 3000})
nodeAlive = await axios('http://' + nodeIP, { timeout: 3000 })
.then(() => true, () => false)
log(`${new Date().toLocaleTimeString()} ${nodeIP} is ${nodeAlive ? 'alive' : 'down'}`)

Expand Down Expand Up @@ -532,13 +533,13 @@ async function main () {
}
module.exports = Object.assign(
main()
.catch(err => {
logError(err)
throw err
})
.then(() => ({
shutdown,
processes: {baseserverProcess},
analytics: ANALYTICS
}))
.catch(err => {
logError(err)
handleCrash(err)
})
.then(() => ({
shutdown,
processes: { baseserverProcess },
analytics: ANALYTICS
}))
)
2 changes: 1 addition & 1 deletion app/src/renderer/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
modal-help
session(v-else)
notifications(:notifications='notifications' theme='cosmos')
modal-error(v-if="config.modals.error.active")
modal-error(v-if='config.modals.error.active' :body='config.modals.error.message')
</template>

<script>
Expand Down
3 changes: 3 additions & 0 deletions app/src/renderer/components/common/NiModalError.vue
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ export default {
.ni-modal-error__body
margin-bottom 4.5rem
.ni-modal-error__footer
min-width: 31rem
.ni-modal-error__footer .ni-btn
margin-bottom 0
</style>
39 changes: 25 additions & 14 deletions app/src/renderer/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Vuelidate from 'vuelidate'
import shrinkStacktrace from '../helpers/shrink-stacktrace.js'
import axios from 'axios'
import Raven from 'raven-js'
import {remote} from 'electron'
import { remote } from 'electron'
import enableGoogleAnalytics from './google-analytics.js'

const config = require('../../../config')
Expand All @@ -16,6 +16,9 @@ import routes from './routes'
import Node from './node'
import Store from './vuex/store'

// exporting this for testing
let store

// setup sentry remote error reporting and google analytics
const analyticsEnabled = JSON.parse(remote.getGlobal('process').env.COSMOS_ANALYTICS)
if (analyticsEnabled) {
Expand Down Expand Up @@ -51,32 +54,37 @@ async function main () {

let relayPort = getQueryParameter('relay_port')
console.log('Expecting relay-server on port:', relayPort)

console.log('Connecting to node:', nodeIP)
const node = Node(nodeIP, relayPort)

node.lcdConnected()
.then(connected => {
if (connected) {
axios.get(`http://localhost:${relayPort}/startsuccess`)
}
})
.then(connected => {
if (connected) {
axios.get(`http://localhost:${relayPort}/startsuccess`)
}
})

const router = new Router({
scrollBehavior: () => ({ y: 0 }),
routes
})

const store = Store({ node })
store = Store({ node })

let connected = await store.dispatch('checkConnection')
if (connected) {
store.dispatch('nodeSubscribe')
store.dispatch('showInitialScreen')
store.dispatch('subscribeToBlocks')
let error = getQueryParameter('error')
if (error) {
store.commit('setModalError', true)
store.commit('setModalErrorMessage', error)
} else {
let connected = await store.dispatch('checkConnection')
if (connected) {
store.dispatch('nodeSubscribe')
store.dispatch('showInitialScreen')
store.dispatch('subscribeToBlocks')
}
}

return new Vue({
new Vue({
router,
...App,
store
Expand All @@ -85,6 +93,9 @@ async function main () {

main().catch(function (err) { throw err })

// exporting this for testing
module.exports.store = store

function getQueryParameter (name) {
let queryString = window.location.search.substring(1)
let pairs = queryString.split('&')
Expand Down
3 changes: 3 additions & 0 deletions app/src/renderer/vuex/modules/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export default ({ commit }) => {
setModalError (state, value) {
state.modals.error.active = value
},
setModalErrorMessage (state, message) {
state.modals.error.message = message
},
setModalHelp (state, value) {
state.modals.help.active = value
},
Expand Down
7 changes: 6 additions & 1 deletion app/src/renderer/vuex/modules/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ export default function ({ node }) {
dispatch('reconnected')
}
},
nodeSubscribe ({commit, dispatch}) {
async nodeSubscribe ({commit, dispatch}) {
if (state.stopConnecting) return

// the rpc socket can be closed before we can even attach a listener
// so we remember if the connection is open
// we handle the reconnection here so we can attach all these listeners on reconnect
if (!node.rpcOpen) {
await sleep(500)
dispatch('reconnect')
return
}
Expand Down Expand Up @@ -119,3 +120,7 @@ export default function ({ node }) {

return { state, mutations, actions }
}

function sleep (ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
14 changes: 8 additions & 6 deletions test/e2e/wallet.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
let { spawn } = require('child_process')
let { spawn} = require('child_process')
let test = require('tape-promise/tape')
let { getApp, restart } = require('./launch.js')
let { navigate, newTempDir, waitForText, sleep, login, logout, closeNotifications } = require('./common.js')

let binary = process.env.BINARY_PATH

function cliSendCoins (home, to, amount) {
function cliSendCoins(home, to, amount) {
let child = spawn(binary, [
'client', 'tx', 'send',
'--name', 'testkey',
Expand All @@ -21,7 +21,7 @@ function cliSendCoins (home, to, amount) {
}

test('wallet', async function (t) {
let {app, home} = await getApp(t)
let { app, home } = await getApp(t)
await restart(app)

let client = app.client
Expand All @@ -40,7 +40,7 @@ test('wallet', async function (t) {
}

t.test('send', async function (t) {
async function goToSendPage () {
async function goToSendPage() {
await navigate(client, 'Balances')
await $('.ni-li-dt=FERMION').$('..').$('..').click()
}
Expand All @@ -53,9 +53,10 @@ test('wallet', async function (t) {
let denomBtn = (denom) => $(`option=${denom.toUpperCase()}`)

t.test('fermion balance before sending', async function (t) {
await client.waitForExist(`//div[contains(text(), "FERMION")]`, 5000)
let fermionEl = balanceEl('fermion')
let balance = await fermionEl.getText()
t.equal(balance, '9007199254740992', 'fermion balance is correct')
t.equal(balance, '9007199254740992', 'fermion balance is correct')
t.end()
})

Expand Down Expand Up @@ -104,7 +105,7 @@ test('wallet', async function (t) {
t.ok(msg.includes('Success'), 'Send successful')
// close the notifications to have a clean setup for the next tests
await closeNotifications(client)

t.end()
})

Expand All @@ -131,6 +132,7 @@ test('wallet', async function (t) {
await navigate(client, 'Balances')

let fermionEl = () => balanceEl('fermion')
await client.waitForExist(`//div[contains(text(), "FERMION")]`, 5000)
await waitForText(fermionEl, '100', 5000)
t.pass('received mycoin transaction')
t.end()
Expand Down
20 changes: 15 additions & 5 deletions test/unit/helpers/node_mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,24 @@ module.exports = {
seed_phrase: 'a b c d e f g h i j k l'
}),
queryAccount: () => null,
queryNonce: () => ({data: 123}),
queryNonce: () => ({
data: 123
}),
buildSend: () => Promise.resolve(null),
buildDelegate: () => Promise.resolve(null),
buildUnbond: () => Promise.resolve(null),
coinTxs: () => Promise.resolve([]),
candidates: () => Promise.resolve({data: []}),
candidates: () => Promise.resolve({
data: []
}),
sendTx: () => Promise.resolve(),
postTx: () => Promise.resolve({
check_tx: { code: 0 },
deliver_tx: { code: 0 }
check_tx: {
code: 0
},
deliver_tx: {
code: 0
}
}),
sign: () => Promise.resolve(null),

Expand All @@ -39,7 +47,9 @@ module.exports = {
subscribe: () => {},
validators: () => mockValidators,
block: (args, cb) => cb({}),
blockchain: (args, cb) => cb(null, {block_metas: {}}),
blockchain: (args, cb) => cb(null, {
block_metas: {}
}),
status: (cb) => cb(null, {
latest_block_height: 42,
node_info: {
Expand Down
15 changes: 10 additions & 5 deletions test/unit/specs/App-w-analytics.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ describe('App with analytics', () => {
jest.mock('raven-js', () => ({
config: (dsn) => {
return ({
install: () => {
}
install: () => {}
})
}
}))
jest.mock('../../../app/src/renderer/google-analytics.js', () => (uid) => {
})
jest.mock('axios', () => ({
get () {}
}))
jest.mock('../../../app/src/renderer/google-analytics.js', () => (uid) => {})
jest.mock('electron', () => ({
remote: {
getGlobal: () => ({
Expand All @@ -29,6 +30,11 @@ describe('App with analytics', () => {
}))

beforeEach(() => {
Object.defineProperty(window.location, 'search', {
writable: true,
value: '?node=localhost&relay_port=8080'
})
document.body.innerHTML = '<div id="app"></div>'
jest.resetModules()
})

Expand All @@ -54,4 +60,3 @@ describe('App with analytics', () => {
require('renderer/main.js')
})
})

Loading

0 comments on commit ef9cb95

Please sign in to comment.