astro_avtourist/scripts/dev.js
2026-04-18 16:19:19 +05:00

191 lines
No EOL
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bun
import { $ } from "bun";
import { spawn } from "child_process";
import path from "path";
import { promisify } from "util";
import net from "net";
const sleep = promisify(setTimeout);
// Проверка занятости порта
async function isPortInUse(port) {
return new Promise((resolve) => {
const server = net.createServer();
server.once("error", () => resolve(true));
server.once("listening", () => {
server.close();
resolve(false);
});
server.listen(port);
});
}
// Принудительное убийство процесса по PID (Windows)
async function killProcess(pid, force = true) {
try {
if (process.platform === "win32") {
await $`taskkill /PID ${pid} ${force ? "/F" : ""}`.quiet();
} else {
process.kill(pid, force ? "SIGKILL" : "SIGTERM");
}
} catch (e) {
// Процесс уже мёртв — ок
}
}
// Поиск и убийство процессов по имени порта
async function killPort(port) {
try {
if (process.platform === "win32") {
// Находим PID по порту
const { stdout } = await $`netstat -ano | findstr :${port}`.quiet().nothrow();
const lines = stdout.toString().trim().split("\n");
const pids = new Set();
for (const line of lines) {
const parts = line.trim().split(/\s+/);
if (parts.length >= 5) {
const pid = parts[4];
if (pid && !isNaN(parseInt(pid))) {
pids.add(parseInt(pid));
}
}
}
for (const pid of pids) {
await killProcess(pid);
console.log(` 🔪 Убит процесс ${pid} на порту ${port}`);
}
} else {
await $`lsof -ti:${port} | xargs kill -9`.quiet().nothrow();
}
} catch (e) {
// Нет процессов — ок
}
}
// Проверка и освобождение портов
async function cleanupPorts() {
console.log("🔍 Проверка портов...");
const ports = [1025, 1080, 4321, 8090];
for (const port of ports) {
if (await isPortInUse(port)) {
console.log(` ⚠️ Порт ${port} занят, освобождаем...`);
await killPort(port);
await sleep(500); // Даём время на освобождение
}
}
}
let maildev, backend, frontend;
// Корректное завершение всех процессов
async function cleanup() {
console.log("\n🛑 Остановка серверов...");
// Принудительно убиваем каждый процесс с SIGKILL
const kills = [];
if (maildev && !maildev.killed) {
maildev.kill("SIGKILL");
kills.push(new Promise(r => maildev.once("exit", r)));
}
if (backend && !backend.killed) {
backend.kill("SIGKILL");
kills.push(new Promise(r => backend.once("exit", r)));
}
if (frontend && !frontend.killed) {
frontend.kill("SIGKILL");
kills.push(new Promise(r => frontend.once("exit", r)));
}
// Ждём завершения не дольше 3 секунд
await Promise.race([
Promise.all(kills),
sleep(3000)
]);
process.exit(0);
}
// Главная функция
async function main() {
await cleanupPorts();
console.log("🚀 Запуск серверов avtourist086...\n");
// Запуск Maildev с отдельной группой процессов
maildev = spawn("maildev", ["--web", "1080", "--smtp", "1025"], {
stdio: "inherit",
shell: true,
windowsHide: true,
detached: false
});
// Запуск PocketBase
backend = spawn("pocketbase.exe", ["serve"], {
cwd: path.join(process.cwd(), "backend"),
stdio: "inherit",
shell: true,
windowsHide: true,
detached: false,
env: {
...process.env,
PB_SMTP_HOST: "localhost",
PB_SMTP_PORT: "1025",
PB_SMTP_FROM: "noreply@avtourist-surgut.ru"
}
});
// Запуск Astro
frontend = spawn("bun", ["dev"], {
cwd: "frontend",
stdio: "inherit",
shell: true,
windowsHide: true,
detached: false
});
// Обработчики сигналов
process.on("SIGINT", cleanup);
process.on("SIGTERM", cleanup);
process.on("SIGBREAK", cleanup); // Windows-specific
// Обработка закрытия консоли Windows
if (process.platform === "win32") {
const readline = await import("readline");
readline.createInterface({
input: process.stdin,
output: process.stdout
}).on("SIGINT", cleanup);
}
// Мониторинг процессов
maildev.on("exit", (code) => {
console.log(`\n📧 Maildev остановлен с кодом ${code}`);
if (code !== 0 && code !== null) cleanup();
});
backend.on("exit", (code) => {
console.log(`\n💾 Backend остановлен с кодом ${code}`);
if (code !== 0 && code !== null) cleanup();
});
frontend.on("exit", (code) => {
console.log(`\n🌐 Frontend остановлен с кодом ${code}`);
cleanup();
});
console.log("✅ Серверы запущены:\n");
console.log(" 📧 Maildev (SMTP): http://localhost:1080");
console.log(" 💾 Backend (PocketBase): http://localhost:8090");
console.log(" 🌐 Frontend (Astro): http://localhost:4321\n");
console.log("Нажмите Ctrl+C для остановки\n");
}
main().catch(err => {
console.error("❌ Ошибка:", err);
process.exit(1);
});