fortify2-js
Version:
MOST POWERFUL JavaScript Security Library! Military-grade cryptography + 19 enhanced object methods + quantum-resistant algorithms + perfect TypeScript support. More powerful than Lodash with built-in security.
158 lines (154 loc) • 5.24 kB
JavaScript
'use strict';
var http = require('http');
/**
* Port Manager - Handles automatic port switching when ports are in use
*/
class PortManager {
constructor(originalPort, config) {
this.originalPort = originalPort;
this.config = {
enabled: false,
maxAttempts: 10,
startPort: originalPort,
strategy: "increment",
...config,
};
}
/**
* Check if a port is available
*/
async isPortAvailable(port, host = "localhost") {
return new Promise((resolve) => {
const server = http.createServer();
let resolved = false;
const cleanup = () => {
if (!resolved) {
resolved = true;
try {
server.close();
}
catch (e) {
// Ignore cleanup errors
}
}
};
// Set a timeout to avoid hanging
const timeout = setTimeout(() => {
cleanup();
resolve(false);
}, 1000);
// Use 127.0.0.1 for port availability check to ensure proper conflict detection
// This works around a Bun issue where multiple servers can bind to "localhost"
const checkHost = host === "localhost" ? "127.0.0.1" : host;
server.listen(port, checkHost, () => {
clearTimeout(timeout);
cleanup();
resolve(true);
});
server.on("error", (err) => {
clearTimeout(timeout);
cleanup();
// EADDRINUSE means port is in use
resolve(err.code !== "EADDRINUSE");
});
});
}
/**
* Generate next port based on strategy
*/
getNextPort(currentPort, attempt) {
const { strategy, portRange, predefinedPorts } = this.config;
switch (strategy) {
case "increment":
return currentPort + attempt;
case "random":
if (portRange) {
const [min, max] = portRange;
return Math.floor(Math.random() * (max - min + 1)) + min;
}
return currentPort + Math.floor(Math.random() * 1000) + 1;
case "predefined":
if (predefinedPorts && predefinedPorts.length > 0) {
return predefinedPorts[attempt % predefinedPorts.length];
}
// Fallback to increment if no predefined ports
return currentPort + attempt;
default:
return currentPort + attempt;
}
}
/**
* Validate port number
*/
isValidPort(port) {
return port >= 1 && port <= 65535;
}
/**
* Find an available port automatically
*/
async findAvailablePort(host = "localhost") {
const result = {
success: false,
port: this.originalPort,
originalPort: this.originalPort,
attempts: 0,
switched: false,
};
// If auto port switch is disabled, just check the original port
if (!this.config?.enabled) {
const available = await this.isPortAvailable(this.originalPort, host);
result.success = available;
result.attempts = 1;
return result;
}
const { maxAttempts, startPort, portRange } = this.config;
let currentPort = startPort || this.originalPort;
// First, try the original port
if (await this.isPortAvailable(this.originalPort, host)) {
result.success = true;
result.attempts = 1;
return result;
}
// If original port is not available, start searching
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
currentPort = this.getNextPort(startPort || this.originalPort, attempt);
// Validate port range if specified
if (portRange) {
const [min, max] = portRange;
if (currentPort < min || currentPort > max) {
continue;
}
}
// Validate port number
if (!this.isValidPort(currentPort)) {
continue;
}
result.attempts = attempt + 1;
if (await this.isPortAvailable(currentPort, host)) {
result.success = true;
result.port = currentPort;
result.switched = true;
// Call the callback if provided
if (this.config?.onPortSwitch) {
this.config.onPortSwitch(this.originalPort, currentPort);
}
break;
}
}
return result;
}
/**
* Get configuration summary
*/
getConfig() {
return { ...this.config };
}
/**
* Update configuration
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
}
}
exports.PortManager = PortManager;
//# sourceMappingURL=PortManager.js.map