@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
81 lines (71 loc) • 2.73 kB
text/typescript
// SPDX-License-Identifier: Apache-2.0
import net from 'node:net';
import * as constants from '../../core/constants.js';
import {type SoloLogger} from '../../core/logging/solo-logger.js';
/**
* Utility class for port-related operations
*/
export class PortUtilities {
/**
* Check if a TCP port is available on the local machine
* @param port Port number to check
* @returns Promise that resolves to true if port is available, false otherwise
*/
public static async isPortAvailable(port: number): Promise<boolean> {
return new Promise<boolean>((resolve, reject): void => {
const server: net.Server = net.createServer();
const timeout: NodeJS.Timeout = setTimeout((): void => {
server.close();
reject(new Error(`Timeout while checking port ${port}`));
}, 5000); // 5-second timeout
server.once('error', (error): void => {
clearTimeout(timeout);
if ((error as NodeJS.ErrnoException).code === 'EADDRINUSE') {
// Port is in use
resolve(false);
} else {
// Unexpected error
reject(error);
}
});
server.once('listening', (): void => {
clearTimeout(timeout);
// Port is available
server.close((): void => {
resolve(true);
});
});
server.listen(port, constants.LOCAL_HOST);
});
}
/**
* Find an available port starting from the given port
* @param startPort Port number to start checking from
* @param timeoutMs Timeout in milliseconds before giving up (default: 30000)
* @param logger logger for debug messages
* @returns Promise that resolves to the first available port or throws an error if timeout is reached
* @throws Error if no available port is found within the timeout period
*/
public static async findAvailablePort(
startPort: number,
timeoutMs: number = 30_000,
logger: SoloLogger,
): Promise<number> {
if (!Number.isInteger(startPort) || startPort < 1 || startPort > 65_535) {
throw new Error(`Invalid startPort: ${startPort}. Must be an integer between 1 and 65535.`);
}
let port: number = startPort;
const startTime: number = Date.now();
while (!(await this.isPortAvailable(port))) {
logger.debug(`Port ${port} is not available, trying ${port + 1}`);
port++;
if (Date.now() - startTime > timeoutMs) {
const errorMessage: string = `Failed to find an available port after ${timeoutMs}ms timeout, starting from port ${startPort}`;
logger.error(errorMessage);
throw new Error(errorMessage);
}
}
return port;
}
}
// The managePortForward function has been moved to components-data-wrapper.ts