Files
wgServer/internal/database/pidfile.go
2025-10-16 16:27:36 +07:00

122 lines
3.4 KiB
Go
Raw Permalink 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.

package database
import (
"fmt"
"log"
"os"
"os/exec"
"strconv"
"strings"
"syscall"
)
const pidFile = "/opt/wg_serf/wg_serf.pid"
// CheckAndKillOldProcess проверяет и завершает старый процесс
func CheckAndKillOldProcess() error {
// Проверяем существует ли PID файл
if _, err := os.Stat(pidFile); os.IsNotExist(err) {
// Файла нет - это первый запуск
return nil
}
// Читаем PID из файла
data, err := os.ReadFile(pidFile)
if err != nil {
log.Println("⚠️ Не удалось прочитать PID файл:", err)
return nil
}
oldPID, err := strconv.Atoi(strings.TrimSpace(string(data)))
if err != nil {
log.Println("⚠️ Некорректный PID в файле:", err)
os.Remove(pidFile)
return nil
}
// Проверяем существует ли процесс
if !processExists(oldPID) {
log.Println("📝 Старый процесс не найден, очищаю PID файл")
os.Remove(pidFile)
return nil
}
// Проверяем что это действительно wg-panel
if !isWGPanelProcess(oldPID) {
log.Println("⚠️ PID принадлежит другому процессу, очищаю файл")
os.Remove(pidFile)
return nil
}
// Завершаем старый процесс
log.Printf("🔄 Обнаружена запущенная версия (PID: %d), завершаю...", oldPID)
if err := killProcess(oldPID); err != nil {
return fmt.Errorf("не удалось завершить старый процесс: %v", err)
}
log.Println("✅ Старый процесс завершен")
os.Remove(pidFile)
return nil
}
// WritePIDFile записывает PID текущего процесса в файл
func WritePIDFile() error {
pid := os.Getpid()
return os.WriteFile(pidFile, []byte(fmt.Sprintf("%d", pid)), 0644)
}
// RemovePIDFile удаляет PID файл
func RemovePIDFile() {
os.Remove(pidFile)
}
// processExists проверяет существует ли процесс с данным PID
func processExists(pid int) bool {
process, err := os.FindProcess(pid)
if err != nil {
return false
}
// Отправляем сигнал 0 для проверки существования процесса
err = process.Signal(syscall.Signal(0))
return err == nil
}
// isWGPanelProcess проверяет что процесс действительно wg-panel
func isWGPanelProcess(pid int) bool {
// Читаем командную строку процесса
cmdline, err := os.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
if err != nil {
return false
}
// Проверяем что в командной строке есть wg-panel
return strings.Contains(string(cmdline), "wg-panel")
}
// killProcess завершает процесс
func killProcess(pid int) error {
process, err := os.FindProcess(pid)
if err != nil {
return err
}
// Сначала пробуем мягко (SIGTERM)
if err := process.Signal(syscall.SIGTERM); err != nil {
return err
}
// Ждем немного
cmd := exec.Command("sleep", "1")
cmd.Run()
// Проверяем завершился ли процесс
if processExists(pid) {
// Если нет - убиваем принудительно (SIGKILL)
log.Println("⚠️ Процесс не завершился, использую SIGKILL")
return process.Signal(syscall.SIGKILL)
}
return nil
}