fixed problems with simultaneous pair creation

This commit is contained in:
tigerbot 2017-05-29 12:41:12 -06:00
parent a1ac58ddfc
commit fef369519c
3 changed files with 60 additions and 41 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

View File

@ -1,15 +1,15 @@
'use strict';
var server;
var listening = false;
var sock;
var PromiseA = require('bluebird');
var promises = {};
function createServer(cb, prefix) {
function createServer(prefix) {
var os = require('os');
var net = require('net');
var path = require('path');
var sockname = (prefix || 'node-socket-pair') + '.' + require('crypto').randomBytes(16).toString('hex') + '.sock';
var sockname = prefix + '.' + require('crypto').randomBytes(16).toString('hex') + '.sock';
var sock;
if (/^win/.test(os.platform())) {
sock = path.join('\\\\?\\pipe', process.cwd(), sockname);
}
@ -17,52 +17,67 @@ function createServer(cb, prefix) {
sock = path.join(os.tmpdir(), sockname);
}
server = net.createServer();
function onServerError(err) {
cb(err);
}
server.once('error', onServerError);
server.once('listening', function () {
listening = true;
server.removeListener('error', onServerError);
var server = net.createServer({allowHalfOpen: true});
promises[prefix] = new PromiseA(function (resolve, reject) {
server.once('error', reject);
server.listen(sock, function () {
server.removeListener('error', reject);
resolve({sock: sock, server: server});
});
});
server.on('close', function () {
delete promises[prefix];
});
return promises[prefix];
}
exports.create = function create(cb, prefix) {
prefix = prefix || 'node-socket-pair';
var net = require('net');
var client = new net.Socket();
var client = new net.Socket({allowHalfOpen: true});
function createConnection() {
function onClientError(err) {
cb(err);
}
client.connect(sock, function () {
client.removeListener('error', onClientError);
if (!promises[prefix]) {
createServer(prefix);
}
// We chain the promises to make sure that we never have multiple pending connections at
// the same time to make sure the pairs are always matched correctly. Otherwise two different
// `onConn` listeners might end up with the same connection.
promises[prefix] = promises[prefix].then(function (result) {
return new PromiseA(function (resolve) {
function onConn(conn) {
cb(null, conn);
resolve(result);
}
result.server.once('connection', onConn);
function onErr(err) {
result.server.removeListener('connection', onConn);
cb(err);
resolve(result);
}
client.once('error', onErr);
client.connect(result.sock, function () {
client.removeListener('error', onErr);
});
});
client.once('error', onClientError);
}
// This server listens on a Unix socket or Windows pipe at 'sock'
if (!server) {
createServer(cb, prefix);
}
server.once('connection', function onEach(connection) {
cb(null, connection);
}, function (err) {
cb(err);
return PromiseA.reject(err);
});
if (!listening) {
server.listen(sock, createConnection);
}
else {
createConnection();
}
return client;
};
exports.closeAll = function () {
if (server) {
server.close();
}
Object.keys(promises).forEach(function (key) {
promises[key].then(function (result) {
result.server.close();
}, function () {
delete promises[key];
});
});
};

View File

@ -23,5 +23,8 @@
"writer"
],
"author": "AJ ONeal <aj@daplie.com> (https://coolaj86.com)",
"license": "MIT OR Apache-2.0"
"license": "MIT OR Apache-2.0",
"dependencies": {
"bluebird": "^3.5.0"
}
}