You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
7.1 KiB
236 lines
7.1 KiB
|
3 months ago
|
#!/usr/bin/env node
|
||
|
|
const { execSync, exec } = require('child_process');
|
||
|
|
const fs = require('fs');
|
||
|
|
const path = require('path');
|
||
|
|
|
||
|
|
// 检查端口是否被占用
|
||
|
|
function isPortTaken(port) {
|
||
|
|
return new Promise((resolve) => {
|
||
|
|
// 在Linux上使用lsof检查端口占用
|
||
|
|
try {
|
||
|
|
execSync(`lsof -i :${port}`, { stdio: 'ignore' });
|
||
|
|
resolve(true);
|
||
|
|
} catch (error) {
|
||
|
|
resolve(false);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 查找占用端口的进程ID
|
||
|
|
function findProcessUsingPort(port) {
|
||
|
|
try {
|
||
|
|
const output = execSync(`lsof -i :${port} | grep LISTEN`, { encoding: 'utf8' });
|
||
|
|
const lines = output.trim().split('\n');
|
||
|
|
if (lines.length > 0) {
|
||
|
|
const parts = lines[0].trim().split(/\s+/);
|
||
|
|
return { pid: parts[1], process: parts[0], user: parts[2] };
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.log(`未找到占用端口 ${port} 的进程`);
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 停止指定进程
|
||
|
|
function stopProcess(pid) {
|
||
|
|
try {
|
||
|
|
execSync(`kill -9 ${pid}`);
|
||
|
|
console.log(`成功停止进程 ${pid}`);
|
||
|
|
return true;
|
||
|
|
} catch (error) {
|
||
|
|
console.error(`停止进程 ${pid} 失败:`, error.message);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 修改PM2配置文件中的端口
|
||
|
|
function updatePM2ConfigFile(newPort) {
|
||
|
|
const configPath = path.join(__dirname, 'ecosystem.config.js');
|
||
|
|
try {
|
||
|
|
let content = fs.readFileSync(configPath, 'utf8');
|
||
|
|
|
||
|
|
// 备份配置文件
|
||
|
|
const backupPath = configPath + '.bak.' + Date.now();
|
||
|
|
fs.writeFileSync(backupPath, content);
|
||
|
|
console.log(`已创建配置备份: ${backupPath}`);
|
||
|
|
|
||
|
|
// 修改production环境端口
|
||
|
|
content = content.replace(/PORT:\s*3001/g, `PORT: ${newPort}`);
|
||
|
|
|
||
|
|
fs.writeFileSync(configPath, content);
|
||
|
|
console.log(`已将PM2配置中的端口修改为: ${newPort}`);
|
||
|
|
return true;
|
||
|
|
} catch (error) {
|
||
|
|
console.error('修改PM2配置文件失败:', error.message);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 重启PM2应用
|
||
|
|
function restartPM2App() {
|
||
|
|
try {
|
||
|
|
execSync('pm2 restart ecosystem.config.js', { stdio: 'inherit' });
|
||
|
|
return true;
|
||
|
|
} catch (error) {
|
||
|
|
console.error('重启PM2应用失败:', error.message);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 主函数
|
||
|
|
async function main() {
|
||
|
|
console.log('=== 微信小程序后端服务 - 端口冲突修复工具 ===\n');
|
||
|
|
|
||
|
|
const originalPort = 3001;
|
||
|
|
let newPort = 3001;
|
||
|
|
|
||
|
|
// 检查原始端口是否被占用
|
||
|
|
const isOriginalPortTaken = await isPortTaken(originalPort);
|
||
|
|
|
||
|
|
if (isOriginalPortTaken) {
|
||
|
|
console.log(`发现端口 ${originalPort} 被占用!`);
|
||
|
|
|
||
|
|
// 查找占用进程
|
||
|
|
const processInfo = findProcessUsingPort(originalPort);
|
||
|
|
if (processInfo) {
|
||
|
|
console.log(`占用端口的进程信息:`);
|
||
|
|
console.log(`- 进程ID: ${processInfo.pid}`);
|
||
|
|
console.log(`- 进程名称: ${processInfo.process}`);
|
||
|
|
console.log(`- 用户: ${processInfo.user}`);
|
||
|
|
|
||
|
|
// 询问是否停止该进程
|
||
|
|
const readline = require('readline').createInterface({
|
||
|
|
input: process.stdin,
|
||
|
|
output: process.stdout
|
||
|
|
});
|
||
|
|
|
||
|
|
readline.question(`是否停止该进程以释放端口 ${originalPort}? (y/n): `, (answer) => {
|
||
|
|
readline.close();
|
||
|
|
|
||
|
|
if (answer.toLowerCase() === 'y') {
|
||
|
|
if (stopProcess(processInfo.pid)) {
|
||
|
|
console.log(`端口 ${originalPort} 已被释放,正在重启应用...`);
|
||
|
|
restartPM2App();
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// 查找可用端口
|
||
|
|
console.log('正在查找可用端口...');
|
||
|
|
let foundPort = false;
|
||
|
|
|
||
|
|
for (let i = 3002; i <= 3100; i++) {
|
||
|
|
execSync(`lsof -i :${i}`, { stdio: 'ignore' }, (error) => {
|
||
|
|
if (error) {
|
||
|
|
newPort = i;
|
||
|
|
foundPort = true;
|
||
|
|
|
||
|
|
// 修改PM2配置并重启
|
||
|
|
if (updatePM2ConfigFile(newPort)) {
|
||
|
|
console.log(`已切换到可用端口: ${newPort}`);
|
||
|
|
console.log('正在重启PM2应用...');
|
||
|
|
restartPM2App();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
if (foundPort) break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!foundPort) {
|
||
|
|
console.error('未找到可用端口,请手动指定一个未被占用的端口。');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
console.error('无法确定占用端口的进程,请手动检查端口占用情况。');
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
console.log(`端口 ${originalPort} 未被占用,检查应用状态...`);
|
||
|
|
|
||
|
|
// 检查PM2应用状态
|
||
|
|
try {
|
||
|
|
const statusOutput = execSync('pm2 status wechat-app', { encoding: 'utf8' });
|
||
|
|
console.log(statusOutput);
|
||
|
|
|
||
|
|
// 提示用户重启应用
|
||
|
|
const readline = require('readline').createInterface({
|
||
|
|
input: process.stdin,
|
||
|
|
output: process.stdout
|
||
|
|
});
|
||
|
|
|
||
|
|
readline.question('是否需要重启应用? (y/n): ', (answer) => {
|
||
|
|
readline.close();
|
||
|
|
|
||
|
|
if (answer.toLowerCase() === 'y') {
|
||
|
|
restartPM2App();
|
||
|
|
} else {
|
||
|
|
console.log('操作已取消。');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
console.error('检查PM2应用状态失败:', error.message);
|
||
|
|
console.log('建议尝试手动重启应用: pm2 restart wechat-app');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 提供非交互式修复选项
|
||
|
|
function provideNonInteractiveFix() {
|
||
|
|
console.log('\n=== 非交互式修复选项 ===');
|
||
|
|
console.log('1. 强制释放3001端口并重启应用');
|
||
|
|
console.log('2. 使用备用端口3004并更新配置');
|
||
|
|
console.log('3. 查看当前端口占用情况');
|
||
|
|
|
||
|
|
const readline = require('readline').createInterface({
|
||
|
|
input: process.stdin,
|
||
|
|
output: process.stdout
|
||
|
|
});
|
||
|
|
|
||
|
|
readline.question('请选择修复方式 (1-3): ', (answer) => {
|
||
|
|
readline.close();
|
||
|
|
|
||
|
|
switch (answer) {
|
||
|
|
case '1':
|
||
|
|
const processInfo = findProcessUsingPort(3001);
|
||
|
|
if (processInfo && stopProcess(processInfo.pid)) {
|
||
|
|
console.log('正在重启应用...');
|
||
|
|
restartPM2App();
|
||
|
|
} else {
|
||
|
|
console.log('端口未被占用或无法停止占用进程');
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case '2':
|
||
|
|
if (updatePM2ConfigFile(3004)) {
|
||
|
|
console.log('正在重启应用...');
|
||
|
|
restartPM2App();
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case '3':
|
||
|
|
try {
|
||
|
|
console.log('端口占用情况:');
|
||
|
|
execSync('netstat -tuln | grep 300', { stdio: 'inherit' });
|
||
|
|
} catch (error) {
|
||
|
|
console.log('未找到相关端口占用信息');
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
console.log('无效选项,操作已取消。');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 运行主程序
|
||
|
|
main().catch(err => {
|
||
|
|
console.error('修复过程中发生错误:', err);
|
||
|
|
provideNonInteractiveFix();
|
||
|
|
});
|
||
|
|
|
||
|
|
// 提供帮助信息
|
||
|
|
setTimeout(() => {
|
||
|
|
console.log('\n如果自动修复失败,可以尝试以下手动解决方案:');
|
||
|
|
console.log('1. 检查端口占用: lsof -i :3001 或 netstat -ano | findstr :3001');
|
||
|
|
console.log('2. 停止占用进程: kill -9 [进程ID]');
|
||
|
|
console.log('3. 或者修改PM2配置使用其他端口:');
|
||
|
|
console.log(' - 编辑 ecosystem.config.js 文件');
|
||
|
|
console.log(' - 将 PORT: 3001 修改为其他可用端口');
|
||
|
|
console.log(' - 保存并运行: pm2 restart ecosystem.config.js');
|
||
|
|
}, 1000);
|