Fall back to next port on EADDRINUSE; show dialog and update tray URL
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ const { initialState, mergeState } = require('./state');
|
||||
* @param {string} [opts.overlayDir] Absolute path to the overlay/ directory to serve as static files. Optional (omit for tests).
|
||||
* @returns {Promise<{ setState: (update: object) => object, stop: () => Promise<void> }>}
|
||||
*/
|
||||
function startServer({ port, overlayDir }) {
|
||||
async function startServer({ port, overlayDir }) {
|
||||
let currentState = { ...initialState };
|
||||
|
||||
const app = express();
|
||||
@@ -82,13 +82,49 @@ function startServer({ port, overlayDir }) {
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
server.listen(port, '127.0.0.1', () => {
|
||||
console.log(`[wtm] server listening on http://127.0.0.1:${port}`);
|
||||
resolve({ setState, stop });
|
||||
});
|
||||
server.on('error', reject);
|
||||
});
|
||||
// Try the preferred port first, then up to 4 sequential fallbacks on EADDRINUSE.
|
||||
const MAX_PORT_ATTEMPTS = 5;
|
||||
let actualPort = null;
|
||||
let lastErr = null;
|
||||
|
||||
// The WebSocketServer re-emits server 'error' events on itself.
|
||||
// Add a no-op sink so Node doesn't crash on unhandled 'error' during port scanning.
|
||||
const wssErrorSink = () => {};
|
||||
wss.on('error', wssErrorSink);
|
||||
|
||||
for (let i = 0; i < MAX_PORT_ATTEMPTS; i++) {
|
||||
const tryPort = port + i;
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
const onError = (err) => {
|
||||
server.removeListener('listening', onListening);
|
||||
reject(err);
|
||||
};
|
||||
const onListening = () => {
|
||||
server.removeListener('error', onError);
|
||||
resolve();
|
||||
};
|
||||
server.once('error', onError);
|
||||
server.once('listening', onListening);
|
||||
server.listen(tryPort, '127.0.0.1');
|
||||
});
|
||||
actualPort = tryPort;
|
||||
break;
|
||||
} catch (err) {
|
||||
lastErr = err;
|
||||
if (err.code !== 'EADDRINUSE') throw err;
|
||||
// EADDRINUSE — fall through and try the next port.
|
||||
}
|
||||
}
|
||||
|
||||
wss.removeListener('error', wssErrorSink);
|
||||
|
||||
if (actualPort === null) {
|
||||
throw lastErr || new Error(`No free port in range ${port}..${port + MAX_PORT_ATTEMPTS - 1}`);
|
||||
}
|
||||
|
||||
console.log(`[wtm] server listening on http://127.0.0.1:${actualPort}`);
|
||||
return { setState, stop, port: actualPort };
|
||||
}
|
||||
|
||||
module.exports = { startServer };
|
||||
|
||||
Reference in New Issue
Block a user