Merge dev: Add automatic port finder
Some checks failed
CI/CD / lint-and-build (push) Has been cancelled
Some checks failed
CI/CD / lint-and-build (push) Has been cancelled
This commit is contained in:
commit
382b584740
77
backend/lib/portFinder.js
Normal file
77
backend/lib/portFinder.js
Normal file
@ -0,0 +1,77 @@
|
||||
// Утилита для поиска свободного порта
|
||||
|
||||
const net = require('net');
|
||||
|
||||
/**
|
||||
* Проверяет, свободен ли порт
|
||||
* @param {number} port - Порт для проверки
|
||||
* @returns {Promise<boolean>} - true если порт свободен, false если занят
|
||||
*/
|
||||
function isPortAvailable(port) {
|
||||
return new Promise((resolve) => {
|
||||
const server = net.createServer();
|
||||
|
||||
server.listen(port, () => {
|
||||
server.once('close', () => {
|
||||
resolve(true);
|
||||
});
|
||||
server.close();
|
||||
});
|
||||
|
||||
server.on('error', (err) => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Находит свободный порт начиная с заданного
|
||||
* @param {number} startPort - Начальный порт для поиска
|
||||
* @param {number} maxAttempts - Максимальное количество попыток (по умолчанию 10)
|
||||
* @returns {Promise<number>} - Свободный порт
|
||||
*/
|
||||
async function findFreePort(startPort, maxAttempts = 10) {
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
const port = startPort + i;
|
||||
const available = await isPortAvailable(port);
|
||||
if (available) {
|
||||
return port;
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Не удалось найти свободный порт в диапазоне ${startPort}-${startPort + maxAttempts - 1}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить порт для сервера (проверяет занятость и находит свободный)
|
||||
* @param {number} defaultPort - Порт по умолчанию
|
||||
* @param {boolean} autoFind - Автоматически искать свободный если занят
|
||||
* @returns {Promise<number>} - Порт для использования
|
||||
*/
|
||||
async function getServerPort(defaultPort, autoFind = true) {
|
||||
const available = await isPortAvailable(defaultPort);
|
||||
if (available) {
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
if (!autoFind) {
|
||||
throw new Error(`Порт ${defaultPort} занят`);
|
||||
}
|
||||
|
||||
console.log(`⚠️ Порт ${defaultPort} занят, ищем свободный...`);
|
||||
const freePort = await findFreePort(defaultPort + 1);
|
||||
console.log(`✅ Найден свободный порт: ${freePort}`);
|
||||
return freePort;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isPortAvailable,
|
||||
findFreePort,
|
||||
getServerPort,
|
||||
};
|
||||
|
||||
@ -9,7 +9,11 @@ const errorHandler = require('./middleware/errorHandler');
|
||||
const { generalLimiter } = require('./middleware/rateLimiter');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3001;
|
||||
const { getServerPort } = require('./lib/portFinder');
|
||||
|
||||
// Получаем порт (с автоматическим поиском свободного если нужно)
|
||||
const DEFAULT_PORT = process.env.PORT || 3001;
|
||||
let PORT = DEFAULT_PORT;
|
||||
|
||||
// Middleware
|
||||
app.use(simpleLogger); // Простое логирование запросов
|
||||
@ -63,10 +67,23 @@ app.use((req, res) => {
|
||||
// Обработка ошибок (должен быть последним middleware)
|
||||
app.use(errorHandler);
|
||||
|
||||
// Запуск сервера
|
||||
app.listen(PORT, () => {
|
||||
// Запуск сервера с автоматическим поиском свободного порта
|
||||
(async () => {
|
||||
try {
|
||||
PORT = await getServerPort(DEFAULT_PORT, true);
|
||||
app.listen(PORT, () => {
|
||||
winstonLogger.info(`🚀 Server is running on http://localhost:${PORT}`);
|
||||
winstonLogger.info(`📡 Health check: http://localhost:${PORT}/api/health`);
|
||||
winstonLogger.info(`📝 Environment: ${process.env.NODE_ENV || 'development'}`);
|
||||
});
|
||||
if (PORT !== DEFAULT_PORT) {
|
||||
winstonLogger.info(
|
||||
`ℹ️ Используется порт ${PORT} вместо ${DEFAULT_PORT} (занят)`
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
winstonLogger.error(`❌ Ошибка запуска сервера: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
"dev": "node scripts/devWithPort.js",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
|
||||
42
frontend/scripts/devWithPort.js
Normal file
42
frontend/scripts/devWithPort.js
Normal file
@ -0,0 +1,42 @@
|
||||
// Скрипт для запуска Next.js dev с автоматическим поиском свободного порта
|
||||
|
||||
const { spawn } = require('child_process');
|
||||
const { findFreePort } = require('./findPort');
|
||||
|
||||
const DEFAULT_PORT = 3000;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const port = await findFreePort(DEFAULT_PORT);
|
||||
|
||||
if (port !== DEFAULT_PORT) {
|
||||
console.log(`⚠️ Порт ${DEFAULT_PORT} занят, используем порт ${port}`);
|
||||
} else {
|
||||
console.log(`✅ Порт ${port} свободен`);
|
||||
}
|
||||
|
||||
// Запускаем Next.js dev с найденным портом
|
||||
const nextDev = spawn('npx', ['next', 'dev', '--turbopack', '-p', String(port)], {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
});
|
||||
|
||||
nextDev.on('error', (error) => {
|
||||
console.error('Ошибка запуска Next.js:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
nextDev.on('exit', (code) => {
|
||||
process.exit(code || 0);
|
||||
});
|
||||
|
||||
// Обработка Ctrl+C
|
||||
process.on('SIGINT', () => {
|
||||
nextDev.kill('SIGINT');
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Ошибка поиска порта:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
|
||||
56
frontend/scripts/findPort.js
Normal file
56
frontend/scripts/findPort.js
Normal file
@ -0,0 +1,56 @@
|
||||
// Скрипт для поиска свободного порта для Next.js
|
||||
|
||||
const net = require('net');
|
||||
|
||||
/**
|
||||
* Проверяет, свободен ли порт
|
||||
*/
|
||||
function isPortAvailable(port) {
|
||||
return new Promise((resolve) => {
|
||||
const server = net.createServer();
|
||||
|
||||
server.listen(port, () => {
|
||||
server.once('close', () => {
|
||||
resolve(true);
|
||||
});
|
||||
server.close();
|
||||
});
|
||||
|
||||
server.on('error', () => {
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Находит свободный порт начиная с заданного
|
||||
*/
|
||||
async function findFreePort(startPort, maxAttempts = 10) {
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
const port = startPort + i;
|
||||
const available = await isPortAvailable(port);
|
||||
if (available) {
|
||||
return port;
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Не удалось найти свободный порт в диапазоне ${startPort}-${startPort + maxAttempts - 1}`
|
||||
);
|
||||
}
|
||||
|
||||
// Если запущен как скрипт
|
||||
if (require.main === module) {
|
||||
const startPort = parseInt(process.argv[2]) || 3000;
|
||||
findFreePort(startPort)
|
||||
.then((port) => {
|
||||
console.log(port);
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { isPortAvailable, findFreePort };
|
||||
|
||||
Loading…
Reference in New Issue
Block a user