Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 58 additions & 8 deletions src/utils/port.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,75 @@
import { execSync } from "node:child_process";
import { readFileSync } from "node:fs";
import net from "node:net";

function isWSL2(): boolean {
try {
const versionInfo = readFileSync("/proc/version", "utf8");
return versionInfo.includes("microsoft") && versionInfo.includes("WSL2");
} catch {
return false;
}
}

function killLinuxProcess(port: number): void {
try {
execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: "pipe" });
} catch {
// Process might not be running on Linux side
}
}

function killWindowsProcessViaPsh(port: number): void {
try {
const command = `powershell.exe "Get-NetTCPConnection -LocalPort ${port} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id \$_.OwningProcess -Force -ErrorAction SilentlyContinue }"`;
execSync(command, { stdio: "pipe" });
} catch {
// Process might not be running on Windows side
}
}

function killWSL2Process(port: number): void {
// In WSL2, processes can run on either Linux or Windows side
// We need to check both since we don't know which one is actually using the port
killLinuxProcess(port);
killWindowsProcessViaPsh(port);
}

function killWindowsProcessViaCmd(port: number): void {
const command = `FOR /F "tokens=5" %a in ('netstat -ano ^| findstr :${port}') do taskkill /F /PID %a`;
execSync(command);
}

function killNativeLinuxProcess(port: number): void {
execSync(`lsof -ti:${port} | xargs kill -9`);
}

export async function isPortInUse(port: number): Promise<boolean> {
return new Promise((resolve) => {
const server = net.createServer();
server.once("error", () => resolve(true)); // Port is still in use

server.once("error", () => {
resolve(true); // Port is in use
});

server.once("listening", () => {
server.close(() => resolve(false)); // Port is free
server.close(() => {
resolve(false); // Port is free
});
});

server.listen(port);
});
}

export function killProcessOnPort(port: number) {
export function killProcessOnPort(port: number): void {
try {
if (process.platform === "win32") {
execSync(
`FOR /F "tokens=5" %a in ('netstat -ano ^| findstr :${port}') do taskkill /F /PID %a`,
);
if (isWSL2()) {
killWSL2Process(port);
} else if (process.platform === "win32") {
killWindowsProcessViaCmd(port);
} else {
execSync(`lsof -ti:${port} | xargs kill -9`);
killNativeLinuxProcess(port);
}
} catch (error) {
console.error(`Failed to kill process on port ${port}:`, error);
Expand Down