ordojs
Version:
A revolutionary web framework with compile-time optimizations and unified client-server development
130 lines • 4.3 kB
JavaScript
/**
* @fileoverview OrdoJS CLI - Port Manager
*
* Handles port allocation, detection of conflicts, and finding available ports.
*/
import net from 'net';
import { logger } from '../utils/index.js';
/**
* Port range for automatic allocation
*/
const PORT_RANGE = {
MIN: 3000,
MAX: 3999
};
/**
* PortManager class for handling port allocation and conflict resolution
*/
export class PortManager {
usedPorts;
basePort;
/**
* Create a new PortManager instance
*
* @param basePort - The preferred base port to use (default: 3000)
*/
constructor(basePort = PORT_RANGE.MIN) {
this.usedPorts = new Set();
this.basePort = basePort;
}
/**
* Check if a port is available
*
* @param port - The port to check
* @returns Promise resolving to true if the port is available, false otherwise
*/
async isPortAvailable(port) {
return new Promise((resolve) => {
const server = net.createServer();
server.once('error', (err) => {
const error = err;
if (error.code === 'EADDRINUSE') {
resolve(false);
}
else {
// Other errors also indicate the port is not usable
resolve(false);
}
});
server.once('listening', () => {
// Close the server and resolve with true (port is available)
server.close(() => {
resolve(true);
});
});
// Try to listen on the port
server.listen(port, '127.0.0.1');
});
}
/**
* Find an available port starting from the specified port
*
* @param startPort - The port to start checking from
* @returns Promise resolving to an available port number
*/
async findAvailablePort(startPort = this.basePort) {
// Start from the requested port
let port = startPort;
// Try ports in sequence until we find an available one
while (port <= PORT_RANGE.MAX) {
if (await this.isPortAvailable(port)) {
return port;
}
port++;
}
// If we've exhausted the range, throw an error
throw new Error(`No available ports found in range ${startPort}-${PORT_RANGE.MAX}`);
}
/**
* Allocate a port for a specific service
*
* @param serviceName - Name of the service requesting a port
* @param preferredPort - Preferred port to use if available
* @returns Promise resolving to the allocated port number
*/
async allocatePort(serviceName, preferredPort) {
const startPort = preferredPort || this.basePort;
try {
// Check if the preferred port is available
if (preferredPort && await this.isPortAvailable(preferredPort)) {
this.usedPorts.add(preferredPort);
logger.debug(`Allocated port ${preferredPort} for ${serviceName}`);
return preferredPort;
}
// Find an available port
const port = await this.findAvailablePort(startPort);
this.usedPorts.add(port);
if (preferredPort && port !== preferredPort) {
logger.warn(`Preferred port ${preferredPort} for ${serviceName} was not available, using ${port} instead`);
}
else {
logger.debug(`Allocated port ${port} for ${serviceName}`);
}
return port;
}
catch (error) {
logger.error(`Failed to allocate port for ${serviceName}: ${error instanceof Error ? error.message : String(error)}`);
throw error;
}
}
/**
* Release a previously allocated port
*
* @param port - The port to release
*/
releasePort(port) {
if (this.usedPorts.has(port)) {
this.usedPorts.delete(port);
logger.debug(`Released port ${port}`);
}
}
/**
* Get all currently allocated ports
*
* @returns Set of allocated port numbers
*/
getAllocatedPorts() {
return new Set(this.usedPorts);
}
}
//# sourceMappingURL=port-manager.js.map