[react-packager] Make sure server is listening on socket

This commit is contained in:
Martín Bigio 2015-08-26 16:30:54 -07:00
parent dbdf7f366f
commit 971b70d72f
2 changed files with 75 additions and 52 deletions

View File

@ -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;

View File

@ -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;