0
# Socket Finding
1
2
Unix socket path discovery for finding available socket file paths with configurable directory and permission settings.
3
4
## Capabilities
5
6
### Get Socket Function
7
8
Finds and returns an unbound Unix socket path. Creates necessary directories if they don't exist.
9
10
```javascript { .api }
11
/**
12
* Responds with a unbound socket using the specified directory and base name on the current machine
13
* @param {SocketFinderOptions} [options] - Socket search options
14
* @param {function} [callback] - Callback function (err, socketPath) => void
15
* @returns {Promise<string>} Promise resolving to available socket path (when no callback provided)
16
*/
17
function getSocket(options?: SocketFinderOptions): Promise<string>;
18
function getSocket(callback: (err: Error, socket: string) => void): void;
19
function getSocket(options: SocketFinderOptions, callback: (err: Error, socket: string) => void): void;
20
```
21
22
**Usage Examples:**
23
24
```javascript
25
const portfinder = require('portfinder');
26
27
// Basic usage with callback - uses default path
28
portfinder.getSocket(function (err, socketPath) {
29
if (err) throw err;
30
console.log('Available socket:', socketPath); // e.g., '/tmp/portfinder.sock'
31
});
32
33
// Promise-based usage
34
portfinder.getSocketPromise()
35
.then((socketPath) => {
36
console.log('Available socket:', socketPath);
37
})
38
.catch((err) => {
39
console.error('Error finding socket:', err);
40
});
41
42
// With custom path - callback style
43
portfinder.getSocket({
44
path: '/var/run/myapp.sock'
45
}, function(err, socketPath) {
46
if (err) throw err;
47
console.log('Socket path:', socketPath); // '/var/run/myapp.sock' or '/var/run/myapp1.sock'
48
});
49
50
// With custom directory permissions - Promise style
51
portfinder.getSocket({
52
path: '/tmp/sockets/app.sock',
53
mod: parseInt('755', 8) // Directory permissions in octal
54
})
55
.then(socketPath => {
56
console.log('Socket with custom permissions:', socketPath);
57
});
58
```
59
60
### Get Socket Promise Function
61
62
Promise-based version of getSocket (alias for getSocket without callback).
63
64
```javascript { .api }
65
/**
66
* Responds a promise that resolves to an unbound socket path
67
* @param {SocketFinderOptions} [options] - Socket search options
68
* @returns {Promise<string>} Promise resolving to available socket path
69
*/
70
function getSocketPromise(options?: SocketFinderOptions): Promise<string>;
71
```
72
73
**Usage Example:**
74
75
```javascript
76
const portfinder = require('portfinder');
77
78
// Equivalent to getSocket without callback
79
const socketPath = await portfinder.getSocketPromise({
80
path: '/run/user/1000/app.sock'
81
});
82
console.log('Found socket path:', socketPath);
83
```
84
85
### Next Socket Function
86
87
Gets the next socket path in sequence by incrementing numeric suffix.
88
89
```javascript { .api }
90
/**
91
* Gets the next socket path in sequence from the specified socketPath
92
* @param {string} socketPath - Path to increment from
93
* @returns {string} Next socket path with incremented numeric suffix
94
*/
95
function nextSocket(socketPath: string): string;
96
```
97
98
**Usage Examples:**
99
100
```javascript
101
const portfinder = require('portfinder');
102
103
// Basic increment
104
const currentSocket = '/tmp/app.sock';
105
const nextSocket = portfinder.nextSocket(currentSocket);
106
console.log('Next socket:', nextSocket); // '/tmp/app1.sock'
107
108
// With existing number
109
const numbered = '/tmp/server5.sock';
110
const incremented = portfinder.nextSocket(numbered);
111
console.log('Incremented socket:', incremented); // '/tmp/server6.sock'
112
113
// Manual socket iteration
114
let testSocket = '/var/run/worker.sock';
115
for (let i = 0; i < 5; i++) {
116
console.log('Testing socket:', testSocket);
117
testSocket = portfinder.nextSocket(testSocket);
118
}
119
// Outputs: worker.sock, worker1.sock, worker2.sock, worker3.sock, worker4.sock
120
```
121
122
## Options Interface
123
124
```javascript { .api }
125
/**
126
* Options for socket finding operations
127
*/
128
interface SocketFinderOptions {
129
/**
130
* Path to the socket file to create
131
* Defaults to ${basePath}.sock (e.g., '/tmp/portfinder.sock')
132
*/
133
path?: string;
134
135
/**
136
* Mode to use when creating folder for socket if it doesn't exist
137
* Should be specified in octal format (e.g., parseInt('755', 8))
138
* Defaults to 755 (rwxr-xr-x)
139
*/
140
mod?: number;
141
}
142
```
143
144
## Socket Path Resolution
145
146
### Default Behavior
147
148
```javascript
149
const portfinder = require('portfinder');
150
151
// Uses global basePath setting
152
console.log('Base path:', portfinder.basePath); // '/tmp/portfinder'
153
154
portfinder.getSocketPromise().then(socketPath => {
155
console.log('Default socket:', socketPath); // '/tmp/portfinder.sock'
156
});
157
```
158
159
### Path Conflicts and Resolution
160
161
```javascript
162
const portfinder = require('portfinder');
163
const fs = require('fs');
164
165
// Create a conflicting socket file
166
fs.writeFileSync('/tmp/test.sock', '');
167
168
portfinder.getSocket({ path: '/tmp/test.sock' }, (err, socketPath) => {
169
console.log('Resolved path:', socketPath); // '/tmp/test1.sock'
170
});
171
```
172
173
## Advanced Usage Patterns
174
175
### Application-Specific Sockets
176
177
```javascript
178
const portfinder = require('portfinder');
179
const path = require('path');
180
const os = require('os');
181
182
async function createAppSocket(appName, userId) {
183
const userRunDir = `/run/user/${userId}`;
184
const socketPath = path.join(userRunDir, `${appName}.sock`);
185
186
try {
187
const finalPath = await portfinder.getSocketPromise({
188
path: socketPath,
189
mod: parseInt('700', 8) // Only user can access
190
});
191
192
return finalPath;
193
} catch (err) {
194
// Fallback to temp directory
195
const tempPath = path.join(os.tmpdir(), `${appName}-${userId}.sock`);
196
return await portfinder.getSocketPromise({ path: tempPath });
197
}
198
}
199
200
createAppSocket('myapp', 1000).then(socketPath => {
201
console.log('App socket path:', socketPath);
202
});
203
```
204
205
### Multiple Service Sockets
206
207
```javascript
208
const portfinder = require('portfinder');
209
210
async function allocateServiceSockets() {
211
const services = ['api', 'worker', 'scheduler', 'monitor'];
212
const baseDir = '/var/run/myapp';
213
214
const allocations = await Promise.all(
215
services.map(async (service) => {
216
const socketPath = await portfinder.getSocketPromise({
217
path: `${baseDir}/${service}.sock`,
218
mod: parseInt('755', 8)
219
});
220
return { service, socketPath };
221
})
222
);
223
224
return allocations;
225
}
226
227
allocateServiceSockets().then(allocations => {
228
console.log('Service socket allocations:', allocations);
229
// e.g., [
230
// { service: 'api', socketPath: '/var/run/myapp/api.sock' },
231
// { service: 'worker', socketPath: '/var/run/myapp/worker.sock' },
232
// { service: 'scheduler', socketPath: '/var/run/myapp/scheduler1.sock' }, // if scheduler.sock exists
233
// { service: 'monitor', socketPath: '/var/run/myapp/monitor.sock' }
234
// ]
235
});
236
```
237
238
### Socket Cleanup and Management
239
240
```javascript
241
const portfinder = require('portfinder');
242
const fs = require('fs').promises;
243
244
class SocketManager {
245
constructor() {
246
this.activeSockets = new Set();
247
}
248
249
async createSocket(options) {
250
const socketPath = await portfinder.getSocketPromise(options);
251
this.activeSockets.add(socketPath);
252
return socketPath;
253
}
254
255
async cleanup() {
256
const cleanupPromises = Array.from(this.activeSockets).map(async (socketPath) => {
257
try {
258
await fs.unlink(socketPath);
259
console.log('Cleaned up socket:', socketPath);
260
} catch (err) {
261
if (err.code !== 'ENOENT') {
262
console.error('Failed to cleanup socket:', socketPath, err);
263
}
264
}
265
});
266
267
await Promise.all(cleanupPromises);
268
this.activeSockets.clear();
269
}
270
}
271
272
// Usage
273
const manager = new SocketManager();
274
275
async function example() {
276
const socket1 = await manager.createSocket({ path: '/tmp/service1.sock' });
277
const socket2 = await manager.createSocket({ path: '/tmp/service2.sock' });
278
279
console.log('Created sockets:', socket1, socket2);
280
281
// Cleanup on process exit
282
process.on('exit', () => manager.cleanup());
283
}
284
```
285
286
## Directory Creation Behavior
287
288
When a socket path is requested, portfinder automatically handles directory creation:
289
290
1. **Existing Directory**: If the parent directory exists, uses it directly
291
2. **Missing Directory**: Creates the directory with specified permissions (`mod` option)
292
3. **Recursive Creation**: Creates parent directories as needed using `fs.mkdir` with `recursive: true`
293
4. **Permission Inheritance**: Uses the `mod` option for all created directories in the path
294
295
```javascript
296
const portfinder = require('portfinder');
297
298
// This will create /deep/nested/path/ if it doesn't exist
299
portfinder.getSocket({
300
path: '/deep/nested/path/app.sock',
301
mod: parseInt('755', 8)
302
}).then(socketPath => {
303
console.log('Socket created with full path:', socketPath);
304
});
305
```