From 971b70d72f34483519df06d793a0ee4231b7963d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= Date: Wed, 26 Aug 2015 16:30:54 -0700 Subject: [PATCH] [react-packager] Make sure server is listening on socket --- .../__tests__/SocketInterface-test.js | 12 ++ react-packager/src/SocketInterface/index.js | 115 ++++++++++-------- 2 files changed, 75 insertions(+), 52 deletions(-) diff --git a/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js b/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js index c03f3999..d43d3586 100644 --- a/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js +++ b/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js @@ -26,6 +26,17 @@ describe('SocketInterface', () => { pit('creates socket path by hashing options', () => { const fs = require('fs'); fs.existsSync = jest.genMockFn().mockImpl(() => true); + fs.unlinkSync = jest.genMockFn(); + let callback; + + require('child_process').spawn.mockImpl(() => ({ + on: (event, cb) => callback = cb, + send: (message) => { + setImmediate(() => callback({ type: 'createdServer' })); + }, + unref: () => undefined, + disconnect: () => undefined, + })); // Check that given two equivelant server options, we end up with the same // socket path. @@ -49,6 +60,7 @@ describe('SocketInterface', () => { pit('should fork a server', () => { const fs = require('fs'); fs.existsSync = jest.genMockFn().mockImpl(() => false); + fs.unlinkSync = jest.genMockFn(); let sockPath; let callback; diff --git a/react-packager/src/SocketInterface/index.js b/react-packager/src/SocketInterface/index.js index 470d0fc2..36d8bc66 100644 --- a/react-packager/src/SocketInterface/index.js +++ b/react-packager/src/SocketInterface/index.js @@ -14,6 +14,7 @@ const SocketServer = require('./SocketServer'); const _ = require('underscore'); const crypto = require('crypto'); const fs = require('fs'); +const net = require('net'); const path = require('path'); const tmpdir = require('os').tmpdir(); const {spawn} = require('child_process'); @@ -38,66 +39,76 @@ const SocketInterface = { ); if (fs.existsSync(sockPath)) { - resolve(SocketClient.create(sockPath)); - return; - } - - const logPath = path.join(tmpdir, 'react-packager.log'); - - const timeout = setTimeout( - () => reject( - new Error( - 'Took too long to start server. Server logs: \n' + - fs.readFileSync(logPath, 'utf8') - ) - ), - CREATE_SERVER_TIMEOUT, - ); - - const log = fs.openSync(logPath, 'a'); - - // Enable server debugging by default since it's going to a log file. - const env = _.clone(process.env); - env.DEBUG = 'ReactPackager:SocketServer'; - - // We have to go through the main entry point to make sure - // we go through the babel require hook. - const child = spawn( - process.execPath, - [path.join(__dirname, '..', '..', 'index.js')], - { - detached: true, - env: env, - stdio: ['ipc', log, log] - } - ); - - child.unref(); - - child.on('message', m => { - if (m && m.type && m.type === 'createdServer') { - clearTimeout(timeout); - child.disconnect(); + var sock = net.connect(sockPath); + sock.on('connect', () => { + sock.end(); resolve(SocketClient.create(sockPath)); - } - }); - - - if (options.blacklistRE) { - options.blacklistRE = { source: options.blacklistRE.source }; + }); + sock.on('error', (e) => { + fs.unlinkSync(sockPath); + createServer(resolve, reject, options, sockPath); + }); + } else { + createServer(resolve, reject, options, sockPath); } - - child.send({ - type: 'createSocketServer', - data: { sockPath, options } - }); }); }, listenOnServerMessages() { return SocketServer.listenOnServerIPCMessages(); } - }; +function createServer(resolve, reject, options, sockPath) { + const logPath = path.join(tmpdir, 'react-packager.log'); + + const timeout = setTimeout( + () => reject( + new Error( + 'Took too long to start server. Server logs: \n' + + fs.readFileSync(logPath, 'utf8') + ) + ), + CREATE_SERVER_TIMEOUT, + ); + + const log = fs.openSync(logPath, 'a'); + + // Enable server debugging by default since it's going to a log file. + const env = _.clone(process.env); + env.DEBUG = 'ReactPackager:SocketServer'; + + // We have to go through the main entry point to make sure + // we go through the babel require hook. + const child = spawn( + process.execPath, + [path.join(__dirname, '..', '..', 'index.js')], + { + detached: true, + env: env, + stdio: ['ipc', log, log] + } + ); + + child.unref(); + + child.on('message', m => { + if (m && m.type && m.type === 'createdServer') { + clearTimeout(timeout); + child.disconnect(); + + resolve(SocketClient.create(sockPath)); + } + }); + + if (options.blacklistRE) { + options.blacklistRE = { source: options.blacklistRE.source }; + } + + child.send({ + type: 'createSocketServer', + data: { sockPath, options } + }); +} + module.exports = SocketInterface;