omnichannel-backend/scripts/ensure-port-free.js

147 lines
3.7 KiB
JavaScript

const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
function loadEnvFile(filePath) {
if (!fs.existsSync(filePath)) return {};
return fs
.readFileSync(filePath, 'utf8')
.split(/\r?\n/)
.reduce((acc, line) => {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) return acc;
const separatorIndex = trimmed.indexOf('=');
if (separatorIndex === -1) return acc;
const key = trimmed.slice(0, separatorIndex).trim();
const value = trimmed.slice(separatorIndex + 1).trim();
acc[key] = value;
return acc;
}, {});
}
function getConfiguredPort() {
const env = {
...loadEnvFile(path.resolve(process.cwd(), '.env.development')),
...process.env,
};
return Number(env.PORT || env.BACKEND_PORT || 3001);
}
function getWindowsPids(port) {
const output = execSync(`netstat -ano -p tcp | findstr :${port}`, {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
});
return Array.from(
new Set(
output
.split(/\r?\n/)
.filter((line) => line.includes('LISTENING'))
.map((line) => line.trim().split(/\s+/).at(-1))
.filter(Boolean)
.filter((pid) => pid !== String(process.pid)),
),
);
}
function getUnixPids(port) {
const output = execSync(`lsof -ti tcp:${port} -sTCP:LISTEN`, {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
});
return Array.from(
new Set(
output
.split(/\r?\n/)
.map((pid) => pid.trim())
.filter(Boolean)
.filter((pid) => pid !== String(process.pid)),
),
);
}
function killPid(pid) {
if (process.platform === 'win32') {
execSync(`taskkill /PID ${pid} /F /T`, { stdio: 'ignore' });
return;
}
execSync(`kill -TERM ${pid}`, { stdio: 'ignore' });
}
function getWindowsWhatsappSessionPids() {
const sessionPath = path.resolve(process.cwd(), 'whatsapp-session');
const escapedSessionPath = sessionPath.replace(/\\/g, '\\\\');
const command = [
'Get-CimInstance Win32_Process',
`Where-Object { $_.Name -eq 'chrome.exe' -and $_.CommandLine -like '*${escapedSessionPath}*' }`,
'Select-Object -ExpandProperty ProcessId',
].join(' | ');
const output = execSync(`powershell -NoProfile -Command "${command}"`, {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
});
return Array.from(
new Set(
output
.split(/\r?\n/)
.map((pid) => pid.trim())
.filter(Boolean)
.filter((pid) => pid !== String(process.pid)),
),
);
}
function getUnixWhatsappSessionPids() {
const sessionPath = path.resolve(process.cwd(), 'whatsapp-session');
const output = execSync(`pgrep -f "${sessionPath}"`, {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
});
return Array.from(
new Set(
output
.split(/\r?\n/)
.map((pid) => pid.trim())
.filter(Boolean)
.filter((pid) => pid !== String(process.pid)),
),
);
}
function killWhatsappSessionBrowsers() {
try {
const pids = process.platform === 'win32' ? getWindowsWhatsappSessionPids() : getUnixWhatsappSessionPids();
if (!pids.length) return;
pids.forEach(killPid);
console.log(`Sessao WhatsApp liberada. Processo(s) Chrome encerrado(s): ${pids.join(', ')}`);
} catch {
// Se nao houver processo usando a sessao, seguimos normalmente.
}
}
const port = getConfiguredPort();
killWhatsappSessionBrowsers();
try {
const pids = process.platform === 'win32' ? getWindowsPids(port) : getUnixPids(port);
if (!pids.length) {
process.exit(0);
}
pids.forEach(killPid);
console.log(`Porta ${port} liberada. Processo(s) encerrado(s): ${pids.join(', ')}`);
} catch {
process.exit(0);
}