socket-function 1.2.4 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "1.2.4",
3
+ "version": "1.2.5",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
@@ -20,6 +20,12 @@ import { formatTime } from "./formatting/format";
20
20
  import { getExternalIP, testTCPIsListening } from "./networking";
21
21
  import { forwardPort } from "./forwardPort";
22
22
 
23
+ // When a requested port is taken and useAvailablePortIfPortInUse is set, we scan
24
+ // upwards from this base instead of binding a random OS-assigned port, so restarts
25
+ // land on predictable, consistent ports.
26
+ const PORT_SCAN_START = 13000;
27
+ const PORT_SCAN_COUNT = 10000;
28
+
23
29
  export type SocketServerConfig = (
24
30
  https.ServerOptions & {
25
31
  key: string | Buffer;
@@ -311,52 +317,55 @@ export async function startSocketServer(
311
317
 
312
318
  let port = config.port;
313
319
  if (!SocketFunction.silent) {
314
- console.log(yellow(`Trying to listening on ${host}:${port}`));
320
+ console.log(yellow(`Trying to listen on ${host}:${port}`));
315
321
  }
316
322
 
317
- let listeningPromise = waitUntilListening();
318
- listeningPromise.catch(e => { });
319
-
320
- // Return true if we are listening, false if the address is in use, and throws on other errors
321
- async function waitUntilListening() {
323
+ // Attempts to bind realServer to a single port. Resolves true once the server is
324
+ // actually listening, false if the port is already in use, and rejects on any
325
+ // other error. After an EADDRINUSE the server is still usable, so the caller can
326
+ // simply retry listen() on the next candidate.
327
+ async function tryListen(candidatePort: number): Promise<boolean> {
322
328
  return await new Promise<boolean>((resolve, reject) => {
323
- realServer.once("error", e => {
324
- reject(e);
325
- });
326
- realServer.once("listening", () => {
327
- resolve(false);
328
- });
329
- });
330
- }
331
-
332
- if (config.useAvailablePortIfPortInUse && port) {
333
- realServer.listen(port, host);
334
- let isListening = await new Promise<boolean>((resolve, reject) => {
335
- if (realServer.listening) {
336
- resolve(true);
337
- return;
329
+ function cleanup() {
330
+ realServer.removeListener("error", onError);
331
+ realServer.removeListener("listening", onListening);
338
332
  }
339
- realServer.once("error", e => {
340
- if (e.message.includes("EADDRINUSE")) {
341
- resolve(true);
333
+ function onError(e: NodeJS.ErrnoException) {
334
+ cleanup();
335
+ if (e.code === "EADDRINUSE" || e.message.includes("EADDRINUSE")) {
336
+ resolve(false);
342
337
  } else {
343
338
  reject(e);
344
339
  }
345
- });
346
- realServer.once("listening", () => {
347
- resolve(false);
348
- });
340
+ }
341
+ function onListening() {
342
+ cleanup();
343
+ resolve(true);
344
+ }
345
+ realServer.once("error", onError);
346
+ realServer.once("listening", onListening);
347
+ realServer.listen(candidatePort, host);
349
348
  });
350
- if (!isListening) {
351
- port = 0;
352
- realServer.listen(port, host);
353
- listeningPromise = waitUntilListening();
349
+ }
350
+
351
+ let bound = await tryListen(port);
352
+ if (!bound && config.useAvailablePortIfPortInUse) {
353
+ for (let candidate = PORT_SCAN_START; candidate < PORT_SCAN_START + PORT_SCAN_COUNT; candidate++) {
354
+ if (candidate === port) continue;
355
+ if (await tryListen(candidate)) {
356
+ bound = true;
357
+ port = candidate;
358
+ break;
359
+ }
354
360
  }
355
- } else {
356
- realServer.listen(port, host);
361
+ if (!bound) {
362
+ throw new Error(`Could not find an available port in range ${PORT_SCAN_START}-${PORT_SCAN_START + PORT_SCAN_COUNT - 1} (requested ${config.port})`);
363
+ }
364
+ }
365
+ if (!bound) {
366
+ throw new Error(`Port ${port} is already in use (set useAvailablePortIfPortInUse to fall back to another port)`);
357
367
  }
358
368
 
359
- await listeningPromise;
360
369
  port = (realServer.address() as net.AddressInfo).port;
361
370
 
362
371
  if (config.autoForwardPort && config.public) {