Skip to content

Commit

Permalink
fix: properly serialize & unserialize errors across processes
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewmueller committed Feb 28, 2018
1 parent 7e9b2da commit 8304e4e
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 64 deletions.
40 changes: 34 additions & 6 deletions lib/ipc.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,20 @@ function IPC(process) {
progress.emit.apply(progress, ['data'].concat(sliced(arguments)))
})

emitter.once(`CALL_RESULT_${id}`, function() {
progress.emit.apply(progress, ['end'].concat(sliced(arguments)))
emitter.once(`CALL_RESULT_${id}`, function(err) {
// unserialize errors
err = unserializeError(err)

progress.emit.apply(
progress,
['end'].concat(err).concat(sliced(arguments, 1))
)

emitter.removeAllListeners(`CALL_DATA_${id}`)
progress.removeAllListeners()
progress = undefined
if (callback) {
callback.apply(null, arguments)
callback.apply(null, [err].concat(sliced(arguments, 1)))
}
})

Expand All @@ -117,17 +124,18 @@ function IPC(process) {

emitter.on('CALL', function(id, name) {
var responder = responders[name]
var done = function() {
var done = function(err) {
err = serializeError(err)
emitter.emit.apply(
emitter,
[`CALL_RESULT_${id}`].concat(sliced(arguments))
[`CALL_RESULT_${id}`].concat(err).concat(sliced(arguments, 1))
)
}
done.progress = function() {
emitter.emit.apply(emitter, [`CALL_DATA_${id}`].concat(sliced(arguments)))
}
if (!responder) {
return done(`Nothing responds to "${name}"`)
return done(new Error(`Nothing responds to "${name}"`))
}
try {
responder.apply(null, sliced(arguments, 2).concat([done]))
Expand All @@ -138,3 +146,23 @@ function IPC(process) {

return emitter
}

function serializeError(err) {
if (!(err instanceof Error)) return err
return {
code: err.code,
message: err.message,
details: err.detail,
stack: err.stack || ''
}
}

function unserializeError(err) {
if (!err || !err.message) return err
const e = new Error(err.message)
e.code = err.code || -1
if (err.stack) e.stack = err.stack
if (err.details) e.details = err.details
if (err.url) e.url = err.url
return e
}
10 changes: 4 additions & 6 deletions lib/javascript.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ var execute = `
if(fn.length - 1 == args.length) {
args.push(((err, v) => {
if(err) {
nightmare.reject(err.message || err.toString());
}
if(err) return nightmare.reject(err);
nightmare.resolve(v);
}));
fn.apply(null, args);
Expand All @@ -36,14 +34,14 @@ var execute = `
nightmare.resolve(v);
})
.catch((err) => {
nightmare.reject(err.message || err.toString())
nightmare.reject(err)
});
} else {
nightmare.resolve(response);
}
}
} catch (err) {
nightmare.reject(err.message);
nightmare.reject(err);
}
})()
`
Expand All @@ -61,7 +59,7 @@ var inject = `
var response = (function () { {{!src}} \n})()
nightmare.resolve(response);
} catch (e) {
nightmare.reject(e.message);
nightmare.reject(e);
}
})()
`
Expand Down
6 changes: 3 additions & 3 deletions lib/nightmare.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ function Nightmare(options) {
log.apply(log, arguments)
})

this.child.on('uncaughtException', function(stack) {
const err = new Error('Nightmare runner error')
err.stack = stack
this.child.on('uncaughtException', function(err) {
const e = new Error('Nightmare runner error: ' + err.message)
e.stack = err.stack || ''

const onClose = () => {
throw err
Expand Down
22 changes: 18 additions & 4 deletions lib/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ window.__nightmare = {
resolve: function(value) {
send('response', value)
},
reject: function(message) {
send('error', message)
reject: function(err) {
send('error', error(err))
}
}

// Listen for error events
window.addEventListener(
'error',
function(e) {
send('page', 'error', e.message, (e.error || {}).stack || '')
function(err) {
send('page', 'error', error(err))
},
true
)
Expand Down Expand Up @@ -92,3 +92,17 @@ window.prompt = function(message, defaultResponse) {
window.confirm = function(message, defaultResponse) {
send('page', 'confirm', message, defaultResponse)
}

/**
* Make errors serializeable
*/

function error(err) {
if (!(err instanceof Error)) return err
return {
code: err.code,
message: err.message,
details: err.detail,
stack: err.stack || ''
}
}
62 changes: 33 additions & 29 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const IS_READY = Symbol('isReady')
* Handle uncaught exceptions in the main electron process
*/

process.on('uncaughtException', function(e) {
parent.emit('uncaughtException', e.stack)
process.on('uncaughtException', function(err) {
parent.emit('uncaughtException', err.stack || err.message || String(err))
})

/**
Expand Down Expand Up @@ -206,7 +206,7 @@ app.on('ready', function() {

parent.respondTo('goto', function(url, headers, timeout, done) {
if (!url || typeof url !== 'string') {
return done('goto: `url` must be a non-empty string')
return done(new Error('goto: `url` must be a non-empty string'))
}

var httpReferrer = ''
Expand Down Expand Up @@ -285,7 +285,7 @@ app.on('ready', function() {
cleanup(null, responseData)
}

function cleanup(error, data) {
function cleanup(err, data) {
clearTimeout(timer)
win.webContents.removeListener('did-fail-load', handleFailure)
win.webContents.removeListener(
Expand All @@ -300,7 +300,7 @@ app.on('ready', function() {
win.webContents.removeListener('did-finish-load', handleFinish)
setIsReady(true)
// wait a tick before notifying to resolve race conditions for events
setImmediate(() => done(error, data))
setImmediate(() => done(err, data))
}

// In most environments, loadURL handles this logic for us, but in some
Expand Down Expand Up @@ -373,23 +373,23 @@ app.on('ready', function() {
*/

parent.respondTo('javascript', function(src, done) {
var response = (event, response) => {
renderer.removeListener('error', error)
renderer.removeListener('log', log)
var onresponse = (event, response) => {
renderer.removeListener('error', onerror)
renderer.removeListener('log', onlog)
done(null, response)
}

var error = (event, error) => {
renderer.removeListener('log', log)
renderer.removeListener('response', response)
done(error)
var onerror = (event, err) => {
renderer.removeListener('log', onlog)
renderer.removeListener('response', onresponse)
done(err)
}

var log = (event, args) => parent.emit.apply(parent, ['log'].concat(args))
var onlog = (event, args) => parent.emit.apply(parent, ['log'].concat(args))

renderer.once('response', response)
renderer.once('error', error)
renderer.on('log', log)
renderer.once('response', onresponse)
renderer.once('error', onerror)
renderer.on('log', onlog)

//parent.emit('log', 'about to execute javascript: ' + src);
win.webContents.executeJavaScript(src)
Expand Down Expand Up @@ -490,8 +490,8 @@ app.on('ready', function() {
parent.respondTo('html', function(path, saveType, done) {
// https://github.com/atom/electron/blob/master/docs/api/web-contents.md#webcontentssavepagefullpath-savetype-callback
saveType = saveType || 'HTMLComplete'
win.webContents.savePage(path, saveType, function(error) {
done(error)
win.webContents.savePage(path, saveType, function(err) {
done(err)
})
})

Expand All @@ -508,8 +508,8 @@ app.on('ready', function() {
landscape: false
})

win.webContents.printToPDF(options, function(error, data) {
if (error) return done(arguments)
win.webContents.printToPDF(options, function(err, data) {
if (err) return done(err)
done(null, data)
})
})
Expand All @@ -527,8 +527,8 @@ app.on('ready', function() {
)

parent.emit('log', 'getting cookie: ' + JSON.stringify(details))
win.webContents.session.cookies.get(details, function(error, cookies) {
if (error) return done(error)
win.webContents.session.cookies.get(details, function(err, cookies) {
if (err) return done(err)
done(null, details.name ? cookies[0] : cookies)
})
})
Expand All @@ -549,8 +549,8 @@ app.on('ready', function() {
)

parent.emit('log', 'setting cookie: ' + JSON.stringify(details))
win.webContents.session.cookies.set(details, function(error) {
if (error) done(error)
win.webContents.session.cookies.set(details, function(err) {
if (err) done(err)
else if (!--pending) done()
})
}
Expand Down Expand Up @@ -582,8 +582,8 @@ app.on('ready', function() {
//for each cookie name in cookies,
for (var i = 0, cookie; (cookie = cookies[i]); i++) {
//remove the cookie from the url
win.webContents.session.cookies.remove(url, cookie, function(error) {
if (error) done(error)
win.webContents.session.cookies.remove(url, cookie, function(err) {
if (err) done(err)
else if (!--pending) done()
})
}
Expand All @@ -599,7 +599,10 @@ app.on('ready', function() {
{
storages: ['cookies']
},
done
function(err) {
if (err) return done(err)
return done()
}
)
})

Expand All @@ -618,8 +621,9 @@ app.on('ready', function() {
require: require,
parent: parent
})
fn(name, options, parent, win, renderer, function(error) {
done(error)
fn(name, options, parent, win, renderer, function(err) {
if (err) return done(err)
return done()
})
})

Expand Down
Loading

0 comments on commit 8304e4e

Please sign in to comment.