socketioMEANseed/www/node_modules/portfinder/lib/portfinder.js
www/node_modules/portfinder/lib/portfinder.jsRaw
1/*
2 * portfinder.js: A simple tool to find an open port on the current machine.
3 *
4 * (C) 2011, Charlie Robbins
5 *
6 */
7
8var fs = require('fs'),
9 net = require('net'),
10 path = require('path'),
11 async = require('async'),
12 mkdirp = require('mkdirp').mkdirp;
13
14//
15// ### @basePort {Number}
16// The lowest port to begin any port search from
17//
18exports.basePort = 8000;
19
20//
21// ### @basePath {string}
22// Default path to begin any socket search from
23//
24exports.basePath = '/tmp/portfinder'
25
26//
27// ### function getPort (options, callback)
28// #### @options {Object} Settings to use when finding the necessary port
29// #### @callback {function} Continuation to respond to when complete.
30// Responds with a unbound port on the current machine.
31//
32exports.getPort = function (options, callback) {
33 if (!callback) {
34 callback = options;
35 options = {};
36 }
37
38 options.port = options.port || exports.basePort;
39 options.host = options.host || null;
40 options.server = options.server || net.createServer(function () {
41 //
42 // Create an empty listener for the port testing server.
43 //
44 });
45
46 function onListen () {
47 options.server.removeListener('error', onError);
48 options.server.close();
49 callback(null, options.port)
50 }
51
52 function onError (err) {
53 options.server.removeListener('listening', onListen);
54
55 if (err.code !== 'EADDRINUSE' && err.code !== 'EACCES') {
56 return callback(err);
57 }
58
59 exports.getPort({
60 port: exports.nextPort(options.port),
61 host: options.host,
62 server: options.server
63 }, callback);
64 }
65
66 options.server.once('error', onError);
67 options.server.once('listening', onListen);
68 options.server.listen(options.port, options.host);
69};
70
71//
72// ### function getPorts (count, options, callback)
73// #### @count {Number} The number of ports to find
74// #### @options {Object} Settings to use when finding the necessary port
75// #### @callback {function} Continuation to respond to when complete.
76// Responds with an array of unbound ports on the current machine.
77//
78exports.getPorts = function (count, options, callback) {
79 if (!callback) {
80 callback = options;
81 options = {};
82 }
83
84 var lastPort = null;
85 async.timesSeries(count, function(index, asyncCallback) {
86 if (lastPort) {
87 options.port = exports.nextPort(lastPort);
88 }
89
90 exports.getPort(options, function (err, port) {
91 if (err) {
92 asyncCallback(err);
93 } else {
94 lastPort = port;
95 asyncCallback(null, port);
96 }
97 });
98 }, callback);
99};
100
101//
102// ### function getSocket (options, callback)
103// #### @options {Object} Settings to use when finding the necessary port
104// #### @callback {function} Continuation to respond to when complete.
105// Responds with a unbound socket using the specified directory and base
106// name on the current machine.
107//
108exports.getSocket = function (options, callback) {
109 if (!callback) {
110 callback = options;
111 options = {};
112 }
113
114 options.mod = options.mod || 0755;
115 options.path = options.path || exports.basePath + '.sock';
116
117 //
118 // Tests the specified socket
119 //
120 function testSocket () {
121 fs.stat(options.path, function (err) {
122 //
123 // If file we're checking doesn't exist (thus, stating it emits ENOENT),
124 // we should be OK with listening on this socket.
125 //
126 if (err) {
127 if (err.code == 'ENOENT') {
128 callback(null, options.path);
129 }
130 else {
131 callback(err);
132 }
133 }
134 else {
135 //
136 // This file exists, so it isn't possible to listen on it. Lets try
137 // next socket.
138 //
139 options.path = exports.nextSocket(options.path);
140 exports.getSocket(options, callback);
141 }
142 });
143 }
144
145 //
146 // Create the target `dir` then test connection
147 // against the socket.
148 //
149 function createAndTestSocket (dir) {
150 mkdirp(dir, options.mod, function (err) {
151 if (err) {
152 return callback(err);
153 }
154
155 options.exists = true;
156 testSocket();
157 });
158 }
159
160 //
161 // Check if the parent directory of the target
162 // socket path exists. If it does, test connection
163 // against the socket. Otherwise, create the directory
164 // then test connection.
165 //
166 function checkAndTestSocket () {
167 var dir = path.dirname(options.path);
168
169 fs.stat(dir, function (err, stats) {
170 if (err || !stats.isDirectory()) {
171 return createAndTestSocket(dir);
172 }
173
174 options.exists = true;
175 testSocket();
176 });
177 }
178
179 //
180 // If it has been explicitly stated that the
181 // target `options.path` already exists, then
182 // simply test the socket.
183 //
184 return options.exists
185 ? testSocket()
186 : checkAndTestSocket();
187};
188
189//
190// ### function nextPort (port)
191// #### @port {Number} Port to increment from.
192// Gets the next port in sequence from the
193// specified `port`.
194//
195exports.nextPort = function (port) {
196 return port + 1;
197};
198
199//
200// ### function nextSocket (socketPath)
201// #### @socketPath {string} Path to increment from
202// Gets the next socket path in sequence from the
203// specified `socketPath`.
204//
205exports.nextSocket = function (socketPath) {
206 var dir = path.dirname(socketPath),
207 name = path.basename(socketPath, '.sock'),
208 match = name.match(/^([a-zA-z]+)(\d*)$/i),
209 index = parseInt(match[2]),
210 base = match[1];
211
212 if (isNaN(index)) {
213 index = 0;
214 }
215
216 index += 1;
217 return path.join(dir, base + index + '.sock');
218};