portfree
Version:
A cross-platform CLI tool for managing processes running on specific ports
203 lines • 8.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PortManager = void 0;
const platform_detector_1 = require("../utils/platform-detector");
const validator_1 = require("../utils/validator");
const errors_1 = require("../errors");
const logger_1 = require("../utils/logger");
/**
* Port Manager core business logic
* Coordinates platform adapters to provide cross-platform port management functionality
*/
class PortManager {
constructor(adapter, getPlatformAdapterFn) {
this.adapter = null;
this._initialized = false;
this.logger = (0, logger_1.createLogger)('PortManager');
if (adapter) {
this.adapter = adapter;
this._initialized = true;
}
this.getPlatformAdapterFn = getPlatformAdapterFn || platform_detector_1.getPlatformAdapter;
}
/**
* Initialize the port manager with the appropriate platform adapter
* @throws If platform adapter cannot be initialized
*/
async initialize() {
if (this._initialized) {
this.logger.debug('Port manager already initialized');
return;
}
try {
this.logger.debug('Initializing port manager');
const AdapterClassOrInstance = await this.getPlatformAdapterFn();
// Handle both class constructors and direct instances (for testing)
if (typeof AdapterClassOrInstance === 'function') {
this.adapter = new AdapterClassOrInstance();
}
else if (AdapterClassOrInstance && typeof AdapterClassOrInstance === 'object') {
// For testing - when getPlatformAdapter returns a mock instance
this.adapter = AdapterClassOrInstance;
}
else {
throw new Error('Invalid adapter returned from getPlatformAdapter');
}
this.logger.debug('Platform adapter obtained:', { platform: process.platform });
// Verify adapter compatibility
if (!this.adapter) {
throw new errors_1.SystemError('Failed to create adapter instance');
}
const isCompatible = await this.adapter.isCompatible();
if (!isCompatible) {
this.logger.error('Platform adapter is not compatible with current system');
throw new errors_1.SystemError('Platform adapter is not compatible with current system');
}
this._initialized = true;
this.logger.info('Port manager initialized successfully');
}
catch (error) {
const err = error;
this.logger.error('Failed to initialize port manager:', err.message);
if (error instanceof errors_1.SystemError) {
throw error;
}
throw new errors_1.SystemError(`Failed to initialize port manager: ${err.message}`);
}
}
/**
* Check processes running on the specified port with detailed information
* @param port - Port number to check
* @returns Array of Process objects running on the port
* @throws If port number is invalid or port lookup fails
*/
async checkPort(port) {
// Validate port number
const validPort = (0, validator_1.validatePort)(port);
this.logger.debug('Checking port:', { port: validPort });
// Ensure adapter is initialized
await this.initialize();
if (!this.adapter) {
throw new errors_1.SystemError('Port manager adapter not initialized');
}
try {
const processes = await this.adapter.findProcessByPort(validPort);
this.logger.debug('Port check completed:', { port: validPort, processCount: processes.length });
return processes || [];
}
catch (error) {
const err = error;
this.logger.error('Port check failed:', { port: validPort, error: err.message });
if (error instanceof errors_1.SystemError || error instanceof errors_1.ValidationError ||
error instanceof errors_1.PermissionError || error instanceof errors_1.NetworkError) {
throw error;
}
// Check if this looks like a network-related error
if (err.message.includes('network') || err.message.includes('connection') ||
err.message.includes('timeout') || err.message.includes('unreachable')) {
throw new errors_1.NetworkError(`Network error while checking port ${validPort}: ${err.message}`, validPort, 'port check');
}
throw new errors_1.SystemError(`Failed to check port ${validPort}: ${err.message}`);
}
}
/**
* Kill a process by PID with error handling
* @param pid - Process ID to terminate
* @returns True if process was successfully terminated
* @throws If PID is invalid, insufficient permissions, or process termination fails
*/
async killProcess(pid) {
// Validate PID
const validPid = (0, validator_1.validatePid)(pid);
this.logger.debug('Attempting to kill process:', { pid: validPid });
// Ensure adapter is initialized
await this.initialize();
if (!this.adapter) {
throw new errors_1.SystemError('Port manager adapter not initialized');
}
try {
const success = await this.adapter.killProcess(validPid);
this.logger.info('Process kill attempt completed:', { pid: validPid, success });
return success;
}
catch (error) {
const err = error;
this.logger.error('Process kill failed:', { pid: validPid, error: err.message });
if (error instanceof errors_1.SystemError || error instanceof errors_1.ValidationError ||
error instanceof errors_1.PermissionError || error instanceof errors_1.NetworkError) {
throw error;
}
throw new errors_1.SystemError(`Failed to kill process ${validPid}: ${err.message}`);
}
}
/**
* Get detailed information about a process by PID
* @param pid - Process ID
* @returns Process details object
* @throws If PID is invalid or process details cannot be retrieved
*/
async getProcessDetails(pid) {
// Validate PID
const validPid = (0, validator_1.validatePid)(pid);
// Ensure adapter is initialized
await this.initialize();
if (!this.adapter) {
throw new errors_1.SystemError('Port manager adapter not initialized');
}
try {
const details = await this.adapter.getProcessDetails(validPid);
return details;
}
catch (error) {
const err = error;
if (error instanceof errors_1.SystemError || error instanceof errors_1.ValidationError ||
error instanceof errors_1.PermissionError || error instanceof errors_1.NetworkError) {
throw error;
}
throw new errors_1.SystemError(`Failed to get process details for PID ${validPid}: ${err.message}`);
}
}
/**
* Check if a specific port is available (no processes running on it)
* @param port - Port number to check
* @returns True if port is available, false if occupied
* @throws If port number is invalid or port lookup fails
*/
async isPortAvailable(port) {
// Validate port number
const validPort = (0, validator_1.validatePort)(port);
// Ensure adapter is initialized
await this.initialize();
if (!this.adapter) {
throw new errors_1.SystemError('Port manager adapter not initialized');
}
try {
const processes = await this.adapter.findProcessByPort(validPort);
return !processes || processes.length === 0;
}
catch (error) {
const err = error;
if (error instanceof errors_1.SystemError || error instanceof errors_1.ValidationError ||
error instanceof errors_1.PermissionError || error instanceof errors_1.NetworkError) {
throw error;
}
throw new errors_1.SystemError(`Failed to check port availability ${validPort}: ${err.message}`);
}
}
/**
* Get the current platform adapter instance
* @returns Platform adapter instance or null if not initialized
*/
getAdapter() {
return this.adapter;
}
/**
* Check if the port manager is initialized
* @returns True if initialized
*/
isInitialized() {
return this._initialized;
}
}
exports.PortManager = PortManager;
//# sourceMappingURL=port-manager.js.map