diff --git a/lib/src/child-writer/index.js b/lib/src/child-writer/index.js index 44ed4ab0..3ae9d005 100644 --- a/lib/src/child-writer/index.js +++ b/lib/src/child-writer/index.js @@ -17,6 +17,7 @@ 'use strict'; const EventEmitter = require('events').EventEmitter; +const _ = require('lodash'); const childProcess = require('child_process'); const ipc = require('node-ipc'); const rendererUtils = require('./renderer-utils'); @@ -75,20 +76,39 @@ exports.write = (image, drive, options) => { ipc.config.silent = true; ipc.serve(); - ipc.server.on('error', (error) => { - emitter.emit('error', error); - }); + const terminateServer = () => { + // Turns out we need to destroy all sockets for + // the server to actually close. Otherwise, it + // just stops receiving any further connections, + // but remains open if there are active ones. + _.each(ipc.server.sockets, (socket) => { + socket.destroy(); + }); + + ipc.server.stop(); + }; + + const emitError = (error) => { + terminateServer(); + emitter.emit('error', error); + }; + + ipc.server.on('error', emitError); ipc.server.on('message', (data) => { let message; try { message = JSON.parse(data); } catch (error) { - return emitter.emit('error', new Error(`Invalid message: ${data}`)); + error.description = `${data}, ${error.message}`; + error.message = 'Invalid message from the writer process'; + return emitError(error); } if (!message.command || !message.data) { - return emitter.emit('error', new Error(`Invalid message: ${data}`)); + const error = new Error('Invalid message from the writer process'); + error.description = `No command or data: ${data}`; + return emitError(error); } // The error object is decomposed by the CLI for serialisation @@ -99,7 +119,7 @@ exports.write = (image, drive, options) => { error.code = message.data.code; error.description = message.data.description; error.stack = message.data.stacktrace; - return emitter.emit('error', error); + return emitError(error); } emitter.emit(message.command, message.data); @@ -116,20 +136,17 @@ exports.write = (image, drive, options) => { }); child.stderr.on('data', (data) => { - emitter.emit('error', new Error(data.toString())); + emitError(new Error(data.toString())); // This function causes the `close` event to be emitted child.kill(); }); - child.on('error', (error) => { - ipc.server.stop(); - emitter.emit('error', error); - }); + child.on('error', emitError); child.on('close', (code) => { - ipc.server.stop(); + terminateServer(); if (code === EXIT_CODES.CANCELLED) { return emitter.emit('done', { @@ -138,7 +155,7 @@ exports.write = (image, drive, options) => { } if (code !== EXIT_CODES.SUCCESS && code !== EXIT_CODES.VALIDATION_ERROR) { - return emitter.emit('error', new Error(`Child process exitted with error code: ${code}`)); + return emitError(new Error(`Child process exited with error code: ${code}`)); } }); });